1、java四種引用類(lèi)型
2、JVM內(nèi)存模型
http://www.lxweimin.com/p/1579aafac60b
《深入理解JVM虛擬機(jī)》中JVM內(nèi)存模型可以分為五個(gè)區(qū)域兩種類(lèi)型,兩大塊,一個(gè)是線程私有,一個(gè)是線程共享數(shù)據(jù)區(qū)。
5個(gè)數(shù)據(jù)區(qū)包括:方法區(qū)、堆區(qū)、虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器。
所有線程共享的數(shù)據(jù)區(qū):
- 方法區(qū): 存儲(chǔ)已被虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯后代碼等數(shù)據(jù)。常量池位于方法區(qū),并使用永久代來(lái)實(shí)現(xiàn)方法區(qū)
- 堆區(qū): 我們常說(shuō)用于存放對(duì)象的區(qū)域
線程私有(隔離)數(shù)據(jù)區(qū):
- 虛擬機(jī)棧: 方法執(zhí)行時(shí)創(chuàng)建一個(gè)棧幀,用于存儲(chǔ)局部變量、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。每個(gè)方法一個(gè)棧幀,互不干擾
- 本地方法棧: 用于存放執(zhí)行native方法的運(yùn)行數(shù)據(jù)
- 程序計(jì)數(shù)器: 當(dāng)前線程所執(zhí)行的字節(jié)碼的指示器,通過(guò)改變計(jì)數(shù)器來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令
上面基本都能理解,但是需要著重理解下虛擬機(jī)棧和本地方法棧,虛擬機(jī)棧是java方法的內(nèi)存區(qū)域,調(diào)用一個(gè)方法就會(huì)創(chuàng)建一個(gè)棧幀,用來(lái)存儲(chǔ)局部變量,用于存儲(chǔ)局部變量表、方法出口等信息,棧是動(dòng)態(tài)創(chuàng)建和消亡的,方法調(diào)用結(jié)束,則棧幀就消失。而,本地方法棧是為java的native方法服務(wù)。
native方法是什么?
3、垃圾回收
https://blog.csdn.net/justloveyou_/article/details/71216049
- 那些內(nèi)存需要回收?(對(duì)象是否可以被回收的兩種經(jīng)典算法: 引用計(jì)數(shù)法 和 可達(dá)性分析算法)
- 什么時(shí)候回收? (堆的新生代、老年代、永久代的垃圾回收時(shí)機(jī),MinorGC 和 FullGC)
- 如何回收?(三種經(jīng)典垃圾回收算法(標(biāo)記清除算法、復(fù)制算法、標(biāo)記整理算法)及分代收集算法 和 七種垃圾收集器)
對(duì)象存活判斷
1)引用計(jì)數(shù)
簡(jiǎn)單咯,略
2)可達(dá)性分析:
通過(guò)一些列稱(chēng)為“GC roots”的對(duì)象作為起始點(diǎn),開(kāi)始向下搜索,走過(guò)的路徑稱(chēng)為引用鏈,,當(dāng)一個(gè)對(duì)象沒(méi)有路徑到達(dá)任意的GC roots時(shí),圖論中說(shuō)法就是不可達(dá),則表示對(duì)象不可用,可以回收。
垃圾收集
1)標(biāo)記清除算法
從根節(jié)點(diǎn)開(kāi)始遍歷,先對(duì)遍歷到的節(jié)點(diǎn)進(jìn)行標(biāo)記,然后掃描整個(gè)空間中未被標(biāo)記的部分,進(jìn)行回收。
標(biāo)記-清除算法的主要不足有兩個(gè):
效率問(wèn)題:標(biāo)記和清除兩個(gè)過(guò)程的效率都不高;
空間問(wèn)題:標(biāo)記-清除算法不需要進(jìn)行對(duì)象的移動(dòng),并且僅對(duì)不存活的對(duì)象進(jìn)行處理,因此標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí),無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作.
2) 復(fù)制算法
復(fù)制算法將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了,就將還存活著的對(duì)象復(fù)制到另外一塊上面,然后再把已使用過(guò)的內(nèi)存空間一次清理掉。這種算法適用于對(duì)象存活率低的場(chǎng)景,比如新生代。這樣使得每次都是對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等復(fù)雜情況,只要移動(dòng)堆頂指針,按順序分配內(nèi)存即可,實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效。當(dāng)然缺點(diǎn)就是將內(nèi)存減少到原來(lái)的一半。
當(dāng)然現(xiàn)在的內(nèi)存空間并不需要1:1去劃分,因?yàn)榇蠖鄶?shù)對(duì)象都是“朝生夕死”,生存期短,根據(jù)將新生代內(nèi)存分為一塊較大的Eden空間和兩塊較小的Survivor空間 (如下圖所示),每次使用Eden和其中一塊Survivor。當(dāng)回收時(shí),將Eden和Survivor中還存活著的對(duì)象一次地復(fù)制到另外一塊Survivor空間上,最后清理掉Eden和剛才用過(guò)的Survivor空間。HotSpot虛擬機(jī)默認(rèn)Eden和Survivor的大小比例是 8:1,也就是每次新生代中可用內(nèi)存空間為整個(gè)新生代容量的90% ( 80%+10% ),只有10% 的內(nèi)存會(huì)被“浪費(fèi)”。
新生代中使用復(fù)制算法較低,因?yàn)榇婊顚?duì)象比較少,不需要頻繁復(fù)制。
3) 標(biāo)記整理算法
復(fù)制收集算法在對(duì)象存活率較高時(shí)就要進(jìn)行較多的復(fù)制操作,效率將會(huì)變低。更關(guān)鍵的是,如果不想浪費(fèi)50%的空間,就需要有額外的空間進(jìn)行分配擔(dān)保,以應(yīng)對(duì)被使用的內(nèi)存中所有對(duì)象都100%存活的極端情況,所以在老年代一般不能直接選用這種算法。
標(biāo)記整理算法的標(biāo)記過(guò)程類(lèi)似標(biāo)記清除算法,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理,而是讓所有存活的對(duì)象都向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存,類(lèi)似于磁盤(pán)整理的過(guò)程,該垃圾回收算法適用于對(duì)象存活率高的場(chǎng)景(老年代)
分代收集算法
對(duì)于一個(gè)大型的系統(tǒng),當(dāng)創(chuàng)建的對(duì)象和方法變量比較多時(shí),堆內(nèi)存中的對(duì)象也會(huì)比較多,如果逐一分析對(duì)象是否該回收,那么勢(shì)必造成效率低下。分代收集算法是基于這樣一個(gè)事實(shí):不同的對(duì)象的生命周期(存活情況)是不一樣的,而不同生命周期的對(duì)象位于堆中不同的區(qū)域,因此對(duì)堆內(nèi)存不同區(qū)域采用不同的策略進(jìn)行回收可以提高 JVM 的執(zhí)行效率。當(dāng)代商用虛擬機(jī)使用的都是分代收集算法:新生代對(duì)象存活率低,就采用復(fù)制算法;老年代存活率高,就用標(biāo)記清除算法或者標(biāo)記整理算法。Java堆內(nèi)存一般可以分為新生代、老年代和永久代。
4、類(lèi)加載機(jī)制
先放一放