麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > Java > 正文

Java垃圾回收機制

2019-11-06 06:04:27
字體:
來源:轉載
供稿:網友

什么是java垃圾回收

Java垃圾回收機制(Gabage Collection)是Java與C/C++之間的巨大差距所在,但垃圾回收不是Java的專利,任何編程語言都可以考慮和設計垃圾回收。

垃圾回收考慮三件事情: 1,哪些內存需要回收? 2,什么時候回收? 3,怎么回收?**

Java垃圾回收自動化地幫我們清理不再使用的內存,既然是“自動化”,為什么還要了解? 答:當需要排查內存泄漏和內存溢出問題時,當垃圾回收機制成為更高并發性的瓶頸時,需要人工對這些環節進行監控和調節。

Java垃圾回收的管理范圍?

Java內存分成若干區塊,分別是:程序計數器PRogram Counter Register),虛擬機棧(VM Stack),本地方法棧(Native Method Stack),Java堆(Java Heap)和方法區(Method Area)。

Java虛擬機內存分區——摘自《深入理解Java虛擬機》

其中,程序計數器,虛擬機棧和本地方法棧是與線程同生死共命運的,因此它們的管理邏輯是比較清晰的。而堆和方法區則不一樣,一個接口的不同實現類所需的內存不一樣,一個方法的不同分支所需的內存也不一樣,這些內存的分配需要在程序運行過程中動態管理。分配與回收都是動態的,所謂Java垃圾回收,管理的就是這部分呢。

回到之前我們說過垃圾回收需要思考三個問題:1,哪些內存需要回收? 2,什么時候回收? 3,怎么回收? 這些問題需要一一解答。

第一個問題:哪些內存需要回收?

或者換個說法——如何判斷一個資源是否不再被使用(“死了”)。

對于Java Heap中的對象回收有兩種方案:

1,簡單而清晰的第一種方案——引用計數算法

給對象添加一個引用計數器,當有一個地方引用了這個對象,計數器就加一,當這個引用失效,計數器減一,當計數器值減為0,說明對象“已死”,可以回收。

引用計數法簡單明了,易于實現,但存在問題,比如,無法解決循環引用情況:

如果對象A和對象B相互引用,即A中有一個屬性引用B,B中有一個屬性引用A。當A和B都不在被外部所使用時,他們之間的引用仍然存在,計數器值不為0,所以不會被回收。

因此,引用計數器算法有其局限性。

2,根搜索法

通過一系列被稱為“GC Roots”的對象作為初始點,逐步向下游進行搜索,搜索做走過的路徑稱為“引用鏈”,當一個對象不在任何一條引用鏈上的時間后,說明它已經“死亡”。

在Java語言中,可作為“GC Roots”的對象如下:

1,虛擬機中的引用對象2,方法區中的類靜態屬性引用的對象3,方法區中常量引用的對象4,本地方法棧JNI引用的對象

可以發現無論是通過引用計數器還是根搜索法,垃圾標定都與引用相關。

因此,為了賦予此更大的彈性空間,引用也有了分類之說。

引用的分類根本上是按照:當被引用的對象和GC遭遇,引用的“強硬”程度區分的。“強硬”程度由高到低,分為“強引用”,“軟引用”,“弱引用”,“弱引用”。

強引用:只要強引用還在,GC永遠不會回收。

軟引用:還有用的引用,內存空間充裕不回收,如果回收發現仍然會超出內存,再把軟引用部分回收。

弱引用:沒用的引用,GC二話不說,回收!

虛引用(幽靈引用):一個對象是否存在虛引用,對其生存時間不構成影響,無法通過虛引用獲得對象實例,只是在垃圾回收時,收到一個系統通知。換句話說,虛引用是輔助垃圾回收機制的設計。

這有點像商販和城管的關系。

強引用就是證照齊全,固定門點,城管是不會管的。

軟引用是也有證照,但是流動攤販。城管可以不管你,但如果上頭來檢查,群眾有舉報,那不好意思,城管要遣走你。

弱引用就是不法小販,遇到就絕不姑息。

虛引用就是那小販已經跑了,剩點家什,城管收走,在賬上記上一筆,收繳XXX一件,就完了。

實際實現細節不在這里深入,不保證比喻的準確,在Oracle官方博客有文章專門討論。

回收逃逸

在一個對象被標記為垃圾等待回收過程中,有一次逃脫的機會,就是finalize()方法,當GC要標記一個對象需要回收時,首先進行一次篩選,篩選對象是否覆蓋了finalize()方法或者JVM已經執行過了finalize()方法。finalize()方法是Object類下定義的方法,可以被覆蓋。如果finalize()被重寫并且沒有被執行,就有可能執行。如果在重寫的finalize()方法中給對象了一個新的引用,對象可以逃過一劫。但是如果第二次遇到GC,即finalize()方法已經執行過了,就不再會執行,直接回收。下面例子說明了這個問題(摘自《深入理解Java虛擬機》):

/** * 演示對象因為被GC而調用finalize自我拯救 * 自我拯救只能拯救一次,系統對一個對象的finalize()方法最多只會調用一次 * */public class FinalizeEscapeGC { public static FinalizeEscapeGC SAVE_HOOK=null; public void isAlive(){ System.out.println("I am still alive"); } @Override public void finalize() throws Throwable{ super.finalize(); System.out.println("Finalize method executes"); FinalizeEscapeGC.SAVE_HOOK=this;//重新建立引用,逃過一劫 } public static void main(String[] args) throws InterruptedException { SAVE_HOOK=new FinalizeEscapeGC(); //第一次垃圾回收,可以逃脫 SAVE_HOOK=null; System.gc(); //Finalizer優先級較低,暫停等待它 Thread.sleep(500); if(SAVE_HOOK!=null){ SAVE_HOOK.isAlive(); }else{ System.out.println("No, I am dead :("); } //第二次垃圾回收,逃脫失敗 SAVE_HOOK=null; System.gc(); //Finalizer優先級較低,暫停等待它 Thread.sleep(500); if(SAVE_HOOK!=null){ SAVE_HOOK.isAlive(); }else{ System.out.println("No, I am dead :("); } }}

輸出

Finalize method executesI am still aliveNo, I am dead :(

但,書上說,finalize()是一個很不推薦的方法了。

以上都是關于Java Heap中對象的,而對于方法區,略有區別:

方法區中需要回收的東西較比堆里少的多,回收的效率是比較低的,即每次回收仍然有大比率的對象存活。方法區主要回收兩部分對象:廢棄常量無用類。回收廢棄常量與回收堆中對象類似,根據引用來確定。無用類的判定需要滿足以下條件:

1,該類的所有實例都已經被回收2,加載該類的ClassLoader已經被回收3,該類對應的java.util.Class對象沒有地方在引用,無法在任何地方通過反射訪問此類。

怎么回收

上面回答了“哪些內存需要回收?”的問題,接下來要解釋“怎么回收的問題?”的理論。至于具體“怎么回收”以及“什么時候回收”是由具體虛擬機實現,運行參數設置和程序員編寫程序決定的。

垃圾收集算法?

我發現在我們日常整理物品,清理自己算磁盤的時候,就在實踐著一些垃圾回收的理論。只不過我們沒有將其理論化為具體的概念。了解了垃圾收集的具體算法理論,會發現它們就是我們整理東西時可能潛移默化用到的思路

垃圾收集算法有三個:

1,標記-清除算法 2,標記-復制算法 3,標記-整理算法

1,標記-清除算法

根據上面講的垃圾識別理論,標定完垃圾后,將它們刪除掉,就是最基礎的標記-清除算法。

優點:簡潔,高效 缺點:1,清除之后的內存區間可能變成了“千瘡百孔”的內存碎片,如果要存儲大的對象,可能找不到大的連續內存存儲它。2,標記和清除的效率低。

2,標記-復制算法

根據垃圾標識方法,找到了還“生存”的對象,將它們復制到一塊完整的新內存連續空間中。

優點:1,效率高,復制之后,舊的整塊內存可以整體執行刪除操作。2,回收后的內存空間連續 缺點:1,需要將內存分成兩塊進行相互復制切換,損失有效內存。2,當對象“生還率”高,復制操作開銷大。

實際上,新生代的對象往往“朝生夕死”,因此不需要1:1分割內存,而是分割成一大塊Eden區,和兩小塊Survivor區。每次程序運行時使用Eden區和一個Survivor區。垃圾回收時,將這兩塊的生還對象復制到另一塊Survivor區上。比如Eden區和兩個Survivor區的大小比例是8:1:1,那么程序運行的內存可使用率是90%。但是,存在可能,生還對象超過了Survivor區大小,因此需要另一塊較大區域做擔保,當超出Survivor區域容積,將對象拷貝至擔保區域。所以實際內存區是有新生代和老生代之分,新生代快速進行“短命”對象的垃圾回收,老生代區給新生代區做擔保,將比較“長壽”的對象放入老生代。老生代區做老生代的垃圾回收。

3,標記-整理法

標記-復制法適合于新生代對象,而對于老生代對象,標記整理法更好,標記整理法是將“生還”對象移動到內存一端的連續空間。

優點:空間連續,不降低可用內存率。適合老生代。

從上面的討論可以發現,根據內存對象的生命周期特點,應該采取不同的收集方法,因此在實際虛擬機中,都是將內存區分成若干個區域,采用不同的收集方法,已達到整體的最優方案。

垃圾收集器

根據上面的不同收集算法,以及不同性能面向和多線程支持程度,有不同的垃圾收集器實現。垃圾收集器也在向越來越好越來越復雜發展??傮w的目標是:更高吞吐量(運行用戶程序時間/總時間),更高速度,更短獨占線程時間發展。

垃圾回收器圖:

這里寫圖片描述

內存分配機制 與垃圾回收器相配合的是內存分配機制:一些內存分配的規則例如:

1,優先在Eden區分配 2,大對象直接放老生代區 3,“長壽”對象放老生代

等等

相關資料: http://www.importnew.com/16533.html http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html http://blog.csdn.net/qiutongyeluo/article/details/52901325 《深入理解Java虛擬機》


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 草莓视频久久 | 日日草夜夜操 | 欧美视频一区二区三区在线观看 | 免费高潮在线国 | av手机在线电影 | 日韩欧美动作影片 | 97超视频在线观看 | 永久免费在线观看av | 毛片在哪看 | 中文有码一区二区 | 欧洲色阁中文字幕 | 国产毛片毛片 | 91av在线影院| 黄色片观看 | 成人免费av在线 | 欧美精品亚洲人成在线观看 | 亚洲综合精品 | 宅男噜噜噜66国产在线观看 | 手机免费看一级片 | 黄色片网站在线免费观看 | 有兽焉免费动画 | xp123精品视频 | 久久国产精品无码网站 | 性生活视频一级 | 免费a观看 | 国产免费永久在线观看 | 草b视频在线观看 | 国产精品久久久久无码av | 日韩视频一 | 最近免费观看高清韩国日本大全 | 视频二区国产 | 久久久久久久高清 | 一级啪啪片 | 午夜噜噜噜 | 涩涩屋av| 天天草天天干天天 | 久久久久久久久成人 | av在线免费观看播放 | 欧美一级淫片007 | 精品国产一区二区三区久久久 | 黄色大片在线免费观看 |