標籤:過程 訪問 暫停 交換 理解 存在 收集 學習 靜態屬性
本文章是我在學習Java記憶體回收機制中總結的知識點的整理,在此特別感謝http://www.cnblogs.com/andy-zcx/p/5522836.html和http://blog.csdn.net/zsuguangh/article/details/6429592的部落格。
- 記憶體流失:記憶體流失是指記憶體空間使用完畢後未進行回收操作。一般來說,Java中的記憶體流失是因為記憶體對象生命週期超出其在程式中存在的時間長度
- 記憶體回收意義:解決編程時需要考慮的記憶體管理問題,有效解決記憶體流失問題,充分利用空閑記憶體空間。Java對象不再有範圍的概念,只有對象的引用才具有範圍。
- 基本操作:(1)發現無用對象;(2)回收無用對象佔用的空間,並且釋放成程式可以再次使用的空間。
- 回收時間:記憶體回收具體發生的時間具有不可預知性,大體上說來具有兩種時機:
-
- 編程人員調用JVM的GC介面,但是僅僅只是告知系統想要進行記憶體回收,具體時間由系統決定;
- 當程式運行時如果需要大塊記憶體,而此時無法提供足夠大的塊,則系統會調用GC進行記憶體回收。
- 引用計數法
- 內容:每個對象在被建立時,將該對象執行個體分配給一個變數(稱為引用計數器),變數計數初值設為1,當該對象被引用時,計數值加1,當一個對象執行個體的某個引用超過生命週期或者被設為其他值時,引用計數器減1。當引用計數器值變為0時,可以被當作記憶體回收。(註:該對象執行個體也可能引用了其他對象,因此當該對象被回收時,它引用的所有對象的計數器都要減1.)
- 評價:可以較快地執行,在即時系統下比較方便,但是無法解決循環參考問題。例如,對象a和對象b互相引用,但是a和b的值被賦為null,此時a、b引用的對象已經無法被訪問,但是它們互相引用,導致其引用計數器的值均不為0,此時GC永遠不會回收它們。
- 根搜尋演算法
- 內容:將程式中所有的參考關聯性當作圖,從根節點GC Root對象開始,尋找對應引用的節點,依次類推,所有的引用節點構成一張圖,其餘的節點則認為是未被引用的節點,即無用節點。Java中用作GC Root對象的有:Java虛擬機器棧中引用的對象、方法區中靜態屬性引用的對象、方法區中常量引用的對象、本地方法棧中引用的對象
- 標記-清除演算法
- 內容:從根集合進行掃描,標記存活對象,全部掃描後再掃描未被標記的對象,進行回收。
- 評價:不需要移動對象,只處理不存活對象,當存活對象較多時比較高效,但是會造成記憶體片段。
- 標記-整理演算法
- 內容:在演算法3的基礎上,回收完無用對象後,會將所有存活對象向空閑空間移動,整理空閑記憶體。
- 評價:開銷成本增加,但是解決了片段化問題。
- 註:演算法3、4、5均屬於根搜尋演算法,此處分開描述是為了便於理解。
- copying演算法
- 內容:將記憶體分為對象地區面和空閑地區面,在對象區進行掃描,然後將對象區的所有有效節點依次copy到空閑區,釋放原對象區,此時原對象區變為空白閑區。在對象區和空閑區的切換中完成記憶體回收。
- 評價:減少了控制代碼的回收,同時不會出現片段,但是在切換過程中程式需要暫停。
- 分代演算法
- 內容:基於不同對象生命週期不一樣,將對象分代(共分為三代:新生代、年老代、持久代)處理。
- 新生代:
所有新產生的對象首先都是放在年輕代的。年輕代的目標就是儘可能快速的收集掉那些生命週期短的對象。
新生代記憶體按照8:1:1的比例分為一個eden區和兩個survivor(survivor0,survivor1)區。一個Eden區,兩個 Survivor區(一般而言)。大部分對象在Eden區中產生。回收時先將eden區存活對象複製到一個survivor0區,然後清空eden區,當這個survivor0區也存放滿了時,則將eden區和survivor0區存活對象複製到另一個survivor1區,然後清空eden和這個survivor0區,此時survivor0區是空的,然後將survivor0區和survivor1區交換,即保持survivor1區為空白, 如此往複。
當survivor1區不足以存放 eden和survivor0的存活對象時,就將存活對象直接存放到老年代。若是老年代也滿了就會觸發一次Full GC,也就是新生代、老年代都進行回收
新生代發生的GC也叫做Minor GC,MinorGC發生頻率比較高(不一定等Eden區滿了才觸發)
- 年老代:
- 持久代:
- 用於存放靜態檔案,如Java類、方法等。持久代對記憶體回收沒有顯著影響
Java記憶體回收機制學習心得