java之所以能夠?qū)崿F(xiàn)自動(dòng)內(nèi)存分配搀愧,是因?yàn)閖vm幫我們完成了兩件事
- 幫助對(duì)象分配內(nèi)存
- 幫助回收分配給對(duì)象的內(nèi)存
回收哪些地方的內(nèi)存
jvm內(nèi)存分類(lèi)可見(jiàn)下圖
線程私有的內(nèi)存占用在程序編譯期就是可知的需五,堆和方法區(qū)的內(nèi)存是在程序運(yùn)行期才能確定,GC負(fù)責(zé)處理的就是線程共享的內(nèi)存:堆 方法區(qū)
對(duì)象已死么
應(yīng)該回收哪些對(duì)象占用的內(nèi)存呢,需要找出“死掉”的對(duì)象,兩種方法可以找到
- 引用計(jì)數(shù)法
由于引用計(jì)數(shù)法容易造成兩個(gè)對(duì)象相互循環(huán)引用問(wèn)題,主流jvm并不采用該方法 - 可達(dá)性分析 主流jvm采用的方法
如下圖攀隔,那些無(wú)法到達(dá)GC Roots的對(duì)象皂贩,就是可以被回收的對(duì)象
GCRoots中的對(duì)象包括
- 虛擬機(jī)棧中(局部變量表)引用的對(duì)象
- 方法區(qū)中類(lèi)的靜態(tài)屬性引用的對(duì)象
- 方法區(qū)中常量引用的對(duì)象
- JNI中引用的對(duì)象
那些發(fā)現(xiàn)不能到達(dá)GC Roots的對(duì)象并不會(huì)立即回收,在真正回收之前竞慢,對(duì)象至少要被標(biāo)記兩次先紫。當(dāng)?shù)谝淮伪话l(fā)現(xiàn)不可達(dá)時(shí),該對(duì)象會(huì)被標(biāo)記一次筹煮,同時(shí)調(diào)用此對(duì)象的finalize()方法(如果有);在第二次被發(fā)現(xiàn)不可達(dá)后居夹,對(duì)象被回收败潦。
利用finalisze()方法,對(duì)象可以逃離一次被回收的命運(yùn)准脂,但是只有一次劫扒。逃命方法如下,需要在finalize()方法中給自己加一個(gè)GCRoots中的hook
<pre>
public class EscapeFromGC(){
public static EscapeFromGC hook;
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize mehtod executed!");
EscapeFromGC.hook = this;
}
</pre>
垃圾回收算法
-
標(biāo)記清除(Mark Sweep)算法
顧名思義狸膏,此方法有兩個(gè)階段沟饥,標(biāo)記需要清除的對(duì)象,然后清除湾戳。
有兩個(gè)問(wèn)題- 效率低
- 會(huì)產(chǎn)生很多不連續(xù)內(nèi)存贤旷,分配大對(duì)象時(shí),容易提前引起另一次垃圾回收
-
復(fù)制算法(Copying)
考慮將內(nèi)存分成兩個(gè)一樣大的區(qū)域砾脑,一邊的內(nèi)存用完了幼驶,就把所用存活的對(duì)象放到另一邊內(nèi)存- 效率高,每次針對(duì)某一片內(nèi)存進(jìn)行內(nèi)存回收韧衣,不用考慮內(nèi)存碎片化
-
有一定空間浪費(fèi)
實(shí)際上盅藻,98%的新時(shí)代對(duì)象都是很快要被回收的,所以實(shí)際jvm并不會(huì)按照1:1來(lái)分配內(nèi)存畅铭。而是將內(nèi)存分為一塊較大的Eden區(qū)和兩塊較小的Survival區(qū)氏淑,默認(rèn)比例為8:1:1,這樣實(shí)際上新時(shí)代的可用內(nèi)存為實(shí)際內(nèi)存的90%硕噩。
-
標(biāo)記整理(Mark Compact)算法
根據(jù)老年代的特點(diǎn)(大部分對(duì)象的存活周期長(zhǎng)假残,需要盡可能利用內(nèi)存)
第一步和標(biāo)記清除算法的標(biāo)記一樣,但是第二步不是清除榴徐,而是讓內(nèi)存一次往前移動(dòng)守问,占滿空閑內(nèi)存。 分代(Generational )收集
現(xiàn)代商業(yè)系統(tǒng)采用分帶收集算法坑资,根據(jù)對(duì)象的生存周期把內(nèi)存分為新生代和老生代耗帕。
- 新生代采用復(fù)制算法
- 老生代采用標(biāo)記整理算法
垃圾收集器
垃圾收集器的發(fā)展方向,就是朝著更高效率發(fā)展袱贮。具體在減少GC的時(shí)間
下圖是常用的垃圾收集器仿便,連線表示在新生代和老生代可以一起配合工作的組合
內(nèi)存分配的幾個(gè)原則
- 對(duì)象優(yōu)先在Eden區(qū)域分配
- 大對(duì)象直接進(jìn)入老年代
- 長(zhǎng)期存活對(duì)象進(jìn)入老年代