這篇文章分享Java垃圾回收機制學習總結
記憶體洩漏#:記憶體洩漏是指記憶體空間使用完畢後未回收作業。一般來說,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到空閒區,釋放原物件區,此時原物件區變為空閒區。在物件區和空閒區的切換中完成垃圾回收。
評價:減少了句柄的回收,同時不會出現碎片,但是在切換過程中程式需要暫停。
分代演算法
用於存放靜態文件,如Java類別、方法等。持久代對垃圾回收沒有顯著影響
在年輕代中經歷了N次垃圾回收後仍然存活的對象,就會被放到年老代中。因此,可以認為年老代中存放的都是一些生命週期較長的物件。
記憶體比新生代也大很多(大概比例是1:2),當老年代記憶體滿時觸發Major GC即Full GC,Full GC發生頻率比較低,老年代物件存活時間比較長,存活率標記高。
所有新生成的物件首先都是放在年輕代的。年輕代的目標就是盡可能快速的收集掉那些生命週期短的物件。
新生代記憶體依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垃圾回收機制學習總結的詳細內容。更多資訊請關注PHP中文網其他相關文章!