java能夠自動進行垃圾收集,c++須要手動釋放內存,這個功能將程序員解放出來,能將更多的注意力放在須要實現的業務上,這也是java相對c++的一個巨大優點,jvm有哪些垃圾收集算法呢?java
- 標記清除算法:算法分爲標記和清除兩個階段,首先標記出全部須要回收的對象,在標記完成後統一回收全部被標記的對象
從圖中能夠看出這種算法的缺點在於,垃圾被回收之後形成了大量不連續的內存碎片。碎片太多可能會致使之後須要分配較大對象時,沒法找到連續的足夠內存從而頻繁觸發垃圾收集,下降系統效率。c++
-
複製算法:爲了解決「標記,清除」算法的問題一種被稱爲複製的算法出現了,它將內存平均分爲兩塊,每次只使用其中一塊,當這一塊存滿時觸發垃圾收集,將還存活的對象複製到另外一塊內存,而後將這塊內存清掉,這樣就不會存在內存碎片的問題。程序員
-
標記整理算法:
複製算法在存活對象較多的時候須要複製的操做也較多,最關鍵的是隻能利用一半的內存,標記整理算法能夠解決這個問題,標記整理算法中的標記和標記清除算法同樣,要被回收的對象找出來之後讓全部存活的對象向一端移動,而後將內存的剩餘部分直接清理掉。
1算法
- 分代收集算法:
分代收集算法將內存分爲新生代和老年代,新生代又分爲:較大的Eden區(佔80%)和兩塊Survivor區(各佔10%),剛剛建立的對象存放在新生代的Eden區
,由於絕大多數的對象(98%)都是朝生夕死的,當Eden區沒有足夠的空間的時候虛擬機會發起一次Minor Gc,Minor Gc以後,存活對象會進入其中的一塊Suvivor區,Eden區被清空,若是Suvivor區內存不夠則直接進入老年代。下一次Minor Gc會將Eden和該Suvivor區的存活對象複製到另外一塊Suvivor區,並將Eden區和該Suvivor區清空。
在這裏咱們能夠看到相比複製算法,被浪費的空間只有10%。可是前提是絕大部分(90%)的對象在Mino Gc的時候會被回收,若是不知足這個條件Suvivor區大小不夠,則存活的對象直接進入老年代。
爲何須要Survivor區?
試想一下若是沒有Survior區,每次進行Minor Gc,存活的對象直接進入老年代,老年代內存被佔滿會發生Major Gc,Major Gc執行的速度比Minor Gc慢十倍以上,當有了Survivor區,存活的對象在兩塊Survior區中倒騰,當倒騰的次數達到16次說明這個對象生命力真的很頑強,纔會被放入老年代。這樣就減小了Major Gc發生的頻次。
爲何須要兩塊Survivor區?
爲了不內存碎片化的問題,你們想一想複製算法是如何解決標記清除算法的內存碎片化問題的,將內存分爲大小相等的兩塊,將存活的對象複製到另外一塊內存,這裏也是同樣的道理。數組
老年代:
由於老年代中對象的生命力比較頑強,若是採用複製算法那些存活的對象須要被複制不少次,因此老年代採用的是標記整理算法。jvm
什麼樣的對象會進入老年代呢?ide
- 大對象會直接進入老年代:
所謂的大對象就是指須要大量連續內存空間的對象,典型的大對象就是很長的字符串和數組,若是大對象直接在Eden區分配內存空間會致使Eden和Survior之間的大量內存複製,很消耗性能,因此它會直接進入老年代。
- 長期存活的對象會進入老年代所謂長期存活的對象就是前面所述,來回倒騰十六次還不死的對象。