1. 程式人生 > >JVM垃圾收集

JVM垃圾收集

load java 虛擬機棧 老年代 引用計數器 nat 有一個 中一 比例

判斷對象是否存活的方法:

1、引用計數算法:給一個對象中添加一個引用計數器,每當有一個地方引用它時,計數器就加1,引用失效時,計數器減1,當引用數量為0時,任務對象已經死了

缺點:當對象之間存在相互循環引用時,引用計數算法無法通知GC收集器回收

2、可達性分析算法:判斷一個對象到GC ROOTS是否有任何引用鏈相連,當一個對象到GC ROOTS沒有任何引用鏈相連時,證明此對象是可回收的

在java語言中,可作為GC roots的對象包括下面幾種:

虛擬機棧中引用的對象

方法區中類靜態屬性引用的對象

方法區中常量引用的對象

本地方法棧中JNI(native方法)引用的對象

引用分類:強引用,軟引用,弱引用,虛引用

回收方法區:

很多人認為方法區是沒有垃圾收集的,在方法區中進行垃圾收集的性價比比較低,在堆中,新生代的進行一次垃圾收集一般可以回收70%到95%,而永久代中的垃圾收集效率遠遠低於堆,

但是當大量使用反射,動態代理等這類頻繁自定義classloader的場景都需要虛擬機具備類卸載的功能,以保證永久代不會溢出

垃圾收集算法:

標記-清除法:標記完後,統一回收所有被標記的對象,主要不足是:一個是效率問題,標記和清除兩個過程的效率都不高,另一個是空間的問題,標記清除後會產生大量不連續的內存碎片,空間碎片太多,可能會導致後續需要分配大內存對象時,無法找到足夠連續的內存空間而觸發另外一次垃圾收集動作

復制算法:將內存劃分為兩塊大小相等的區域,當其中一塊用完時,將還存活的對象復制到另外一塊上面,然後再把使用過的內存空間一次清理掉,每次都是對整個半區進行內存回收,內存分配時不用考慮內存碎片等復雜情況

目前虛擬機都采用這種收集算法來回收新生代,將內存劃分為一個較大的eden空間和兩個較小的survivor空間,每次只是用一個eden區間和一個survivor空間,默認大小比例為8:1,也就是每次新生代中可用內存空間為整個新生代容量的90%,只有10%會浪費,另外沒有辦法保證每次回收都只有不多余10%的對象存活,當survivor空間不夠用時,需要依賴其他內存進行分配擔保

標記-整理算法:

復制收集算法在存活率比較高時,會進行較多的復制操作,效率會變低,關鍵時如果不想浪費50%的空間,就需要有額外的空間進行分配擔保,標記-整理算法,後續步驟不是直接對可回收的對象進行清理,而是讓所有存活的對象都像一端移動,然後直接清理掉端邊界以外的內存

分代收集算法:就是根據對象存活周期的不同將內存劃分為幾塊,一般是把java堆分為新生代和老年代,這樣就可以根據各個年代的特點采用最合適的收集算法

JVM垃圾收集