JVM系列之(1) —— JVM內(nèi)存結(jié)構(gòu)和對(duì)象的分配回收

1筹燕、JVM內(nèi)存結(jié)構(gòu)

所以通過(guò)表格的形式概括如下:


注:方法區(qū),位于堆的持久代中蛹含。但1.8以后毅厚,移除持久代,采用元空間浦箱。

2吸耿、堆內(nèi)存結(jié)構(gòu)

JVM參數(shù)

-Xmx: 表示java虛擬機(jī)堆區(qū)內(nèi)存可被分配的最大上限祠锣,通常為操作系統(tǒng)可用內(nèi)存的1/4大小。開(kāi)發(fā)過(guò)程中咽安,通常會(huì)將 -Xms 與 -Xmx兩個(gè)參數(shù)的配置相同的值伴网,其目的是為了能夠在java垃圾回收機(jī)制清理完堆區(qū)后不需要重新分隔計(jì)算堆區(qū)的大小而浪費(fèi)資源。

新生代:

大部分對(duì)象迅速死亡妆棒,存活對(duì)象少澡腾,因而采用“標(biāo)記-清除-復(fù)制”算法。分為eden區(qū)糕珊,s0,动分、s1區(qū)。

新生對(duì)象大部分分配在eden區(qū)红选,當(dāng)eden區(qū)無(wú)法再繼續(xù)分配新對(duì)象時(shí)(不一定eden區(qū)滿(mǎn))澜公,觸發(fā)Minor GC,將消亡的對(duì)象清理掉(作用于 E 區(qū)喇肋、S0區(qū)及 S1 區(qū))坟乾,并將剩余的對(duì)象復(fù)制到 S0 區(qū),此時(shí) S1 區(qū)是空的苟蹈。下一次eden區(qū)無(wú)法再繼續(xù)分配新對(duì)象時(shí)糊渊,,觸發(fā)Minor GC慧脱,并將剩余的對(duì)象復(fù)制到S1區(qū)渺绒,此時(shí)S0區(qū)是空的。也就是說(shuō)S0和S1總有一個(gè)保持為空菱鸥。

當(dāng)新生代對(duì)象經(jīng)歷幾次MinorGC后(HotSpot 默認(rèn)為 15 次宗兼,可通過(guò)-XX:MaxTenuringThreshold控制),會(huì)晉升至老年代氮采。

新生代對(duì)象分配機(jī)制:

jvm參數(shù):

-xmn用于設(shè)置年輕代的大小(等同-XX:newSize = -XX:MaxnewSize = -Xmn )殷绍,建議設(shè)為整個(gè)堆大小的1/3或者1/4,兩個(gè)值設(shè)為一樣大。

-XX:SurvivorRatio 用于設(shè)置Eden和其中一個(gè)Survivor的比值鹊漠,一般E區(qū)和S0主到、S1區(qū)比值是8:1:1。

.-XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold

用于設(shè)置晉升到老年代的對(duì)象年齡的最小值和最大值躯概,每個(gè)對(duì)象在堅(jiān)持過(guò)一次Minor GC之后登钥,年齡就加1。

-XX:+UseTLAB ?默認(rèn)啟用

-XX:TLABWasteTargetPercent:TLAB占eden區(qū)的百分比,默認(rèn)1%

老年代:

老年代采用“標(biāo)記-清除-整理”算法娶靡。

老年代GC為MajorGC牧牢,一般MajorGC都會(huì)伴隨MinorGC(因?yàn)閷?duì)象一般都從新生代晉升老年代,導(dǎo)致老年代空間不足,觸發(fā)MajorGC塔鳍。但非絕對(duì)的伯铣,在 ParallelScavenge 收集器的收集策略里

就有直接進(jìn)行 Major GC 的策略選擇過(guò)程)。FullGC為一次majorGC和MinorGC轮纫。

永久代:

存放常量池和方法區(qū)數(shù)據(jù)腔寡。

JVM參數(shù):

-XX:PermSize和-XX:MaxPermSize來(lái)指定最小值和最大值

3、內(nèi)存分配與回收策略

(1)蜡感、對(duì)象優(yōu)先在Eden分區(qū):

大多數(shù)情況下蹬蚁,對(duì)象在新生代Eden區(qū)中分配。當(dāng)Eden區(qū)沒(méi)有足夠空間分配時(shí)郑兴,虛擬機(jī)發(fā)起一次Minor GC犀斋。GC后對(duì)象嘗試放入Survivor空間,如果Survivor空間無(wú)法放入對(duì)象時(shí)情连,只能通過(guò)空間分配擔(dān)保機(jī)制提前轉(zhuǎn)移到老年代叽粹。

(2)、大對(duì)象直接進(jìn)入老年代:

大對(duì)象指需要大量連續(xù)內(nèi)存空間的Java對(duì)象却舀。虛擬機(jī)提供-XX:PretenureSizeThreshold參數(shù)虫几,如果大于這個(gè)設(shè)置值對(duì)象則直接分配在老年代。這樣可以避免新生代中的Eden區(qū)及兩個(gè)Survivor區(qū)發(fā)生大量?jī)?nèi)存復(fù)制挽拔。

(3)辆脸、長(zhǎng)期存活的對(duì)象進(jìn)入老年代:

虛擬機(jī)會(huì)給每個(gè)對(duì)象定義一個(gè)對(duì)象年齡計(jì)數(shù)器。如果對(duì)象在Eden出生并且經(jīng)過(guò)一次Minor GC后任然存活螃诅,且能夠被Survivor容納啡氢,將被移動(dòng)到Survivor空間中,并且對(duì)象年齡設(shè)為1.每次Minor GC后對(duì)象任然存活在Survivor區(qū)中术裸,年齡就加一倘是,當(dāng)年齡到達(dá)-XX:MaxTenuringThreshold參數(shù)設(shè)定的值時(shí),將會(huì)移動(dòng)到老年代袭艺。

(4)搀崭、動(dòng)態(tài)年齡判斷:

虛擬機(jī)不是永遠(yuǎn)要求對(duì)象的年齡必須達(dá)到-XX:MaxTenuringThreshold設(shè)定的值才會(huì)將對(duì)象移動(dòng)到老年代去。如果Survivor中相同年齡所有對(duì)象大小的總和大于Survivor空間的一半猾编,年齡大于或等于該年齡的對(duì)象可以直接進(jìn)入老年代瘤睹。

(5)、空間分配擔(dān)保:

在Minor GC前答倡,虛擬機(jī)會(huì)檢查老年代最大可用連續(xù)空間是否大于新生代所有對(duì)象總空間默蚌,如果條件成立,那么Minor GC是成立的苇羡。如果不成立,虛擬機(jī)查看HandlePromotionFailure設(shè)置值是否允許擔(dān)保失敗。如果允許设江,那么會(huì)繼續(xù)檢查老年代最大可用連續(xù)空間是否大于歷次移動(dòng)到老年代對(duì)象的平均大小锦茁,如果大于,將嘗試一次Minor GC叉存。如果小于码俩,或者HandlePromotionFailure設(shè)置值不允許冒險(xiǎn),那將進(jìn)行一次Full GC歼捏。

minorgc時(shí)稿存,會(huì)去檢查老年代對(duì)象引用新生代對(duì)象的引用。老年代提供一個(gè)專(zhuān)門(mén)區(qū)域瞳秽,存放這些信息瓣履,提高minorgc檢查效率。

4练俐、觸發(fā)FullGC的條件:

老年代空間不足袖迎、

永久代空間不足、

GC擔(dān)保失敗腺晾、

CMS的Cocurrent mode failure(發(fā)生在cms的清理sweep階段,發(fā)現(xiàn)有新的垃圾產(chǎn)生,而且老年代沒(méi)有足夠空間導(dǎo)致的)

5燕锥、對(duì)象的創(chuàng)建過(guò)程和內(nèi)存分配

指針碰撞(Bump the Pointer):假設(shè)Java堆中內(nèi)存是絕對(duì)規(guī)整的,所有用過(guò)的內(nèi)存都放在一邊悯蝉,空閑的內(nèi)存放在另一邊归形,中間放著一個(gè)指針作為分界點(diǎn)的指示器,那分配內(nèi)存就僅僅是把那個(gè)指針向空閑空間那邊挪動(dòng)一段與對(duì)象大小相等的距離鼻由。

空閑列表(Free List):如果Java堆中的內(nèi)存并不是規(guī)整的暇榴,已使用的內(nèi)存和空閑的內(nèi)存相互交錯(cuò),那么虛擬機(jī)維護(hù)一個(gè)列表嗡靡,并更新列表山的記錄跺撼。

分配內(nèi)存過(guò)程中還需要解決線(xiàn)程安全問(wèn)題。 一個(gè)修改指針操作讨彼,就會(huì)帶來(lái)隱患:對(duì)象 A 正分配內(nèi)存呢歉井,指針還沒(méi)來(lái)得急修改,突然對(duì)象 B 又同時(shí)使用了原來(lái)的指針來(lái)分配 B 的內(nèi)存哈误。解決方案也有兩種:同步處理——實(shí)際上虛擬機(jī)采用 CAS 配上失敗重試來(lái)保證更新操作的原子性哩至。把內(nèi)存分配的動(dòng)作按照線(xiàn)程劃分在不同的空間之中進(jìn)行,即每個(gè)線(xiàn)程在 Java 堆中預(yù)先分配一小塊內(nèi)存蜜自,成為本地線(xiàn)程分配緩存(Thread Local Allocation Buffer菩貌,TLAB)。哪個(gè)線(xiàn)程要分配內(nèi)存重荠,就在哪個(gè)線(xiàn)程的 TLAB 上分配箭阶,用完并分配新的TLAB時(shí),才需要同步鎖定。

對(duì)象頭中主要包括兩部分信息:

一部分用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù)仇参,如哈希碼嘹叫、GC分代年齡、鎖狀態(tài)標(biāo)志诈乒、線(xiàn)程持有的鎖罩扇、偏向線(xiàn)程ID攒霹、偏向時(shí)間戳等验靡。

另一部分是類(lèi)型指針,即對(duì)象指向它的類(lèi)元數(shù)據(jù)的指針杠步,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類(lèi)的實(shí)例肠鲫。如果對(duì)象是Java數(shù)組员帮,那在對(duì)象頭中還必須有一塊記錄數(shù)組長(zhǎng)的數(shù)據(jù)。

實(shí)例數(shù)據(jù)部分是對(duì)象真正存儲(chǔ)的有效信息滩届,也是程序代碼中定義的各種類(lèi)型的字段內(nèi)容集侯。從父類(lèi)繼承下來(lái)的,在子類(lèi)中定義的都需要記錄下來(lái)帜消。

對(duì)齊填充僅僅起到占位符的作用棠枉。HotSpot VM的自動(dòng)內(nèi)存管理系統(tǒng)要求對(duì)象起始地址是8字節(jié)的整數(shù)倍,所以對(duì)象大小必須是8字節(jié)的整數(shù)倍泡挺。當(dāng)對(duì)象實(shí)例數(shù)據(jù)部分沒(méi)有對(duì)齊時(shí)辈讶,需要通過(guò)對(duì)齊填充來(lái)補(bǔ)全。

注:逃逸分析與棧上分配

逃逸分析:就是分析對(duì)象動(dòng)態(tài)作用域:當(dāng)一個(gè)對(duì)象在方法中被定義后娄猫,它可能被外部方法所引用贱除。方法逃逸:例如作為調(diào)用參數(shù)傳遞到其他方法中。線(xiàn)程逃逸:有可能被外部線(xiàn)程訪(fǎng)問(wèn)到媳溺,譬如賦值給類(lèi)變量或可以在其他線(xiàn)程中訪(fǎng)問(wèn)的實(shí)例變量月幌。

棧上分配(Stack Allocation):

如果確定一個(gè)對(duì)象不會(huì)逃逸出方法之外,那讓這個(gè)對(duì)象在棧上分配內(nèi)存將會(huì)是一個(gè)很不錯(cuò)的主意悬蔽,對(duì)象所占用的內(nèi)存空間就可以隨棧幀出棧而銷(xiāo)毀扯躺。在一般應(yīng)用中,不會(huì)逃逸的局部對(duì)象所占的比例很大蝎困,如果能使用棧上分配录语,那大量的對(duì)象就會(huì)隨著方法的結(jié)束而自動(dòng)銷(xiāo)毀了,垃圾收集系統(tǒng)的壓力將會(huì)小很多禾乘。在實(shí)際的應(yīng)用程序澎埠,尤其是大型程序中反而發(fā)現(xiàn)實(shí)施逃逸分析可能出現(xiàn)效果不穩(wěn)定的情況,或因分析過(guò)程耗時(shí)但卻無(wú)法有效判別出非逃逸對(duì)象而導(dǎo)致性能(即時(shí)編譯的收益)有所下降始藕,所以在很長(zhǎng)的一段時(shí)間里蒲稳,即使是Server Compiler氮趋,也默認(rèn)不開(kāi)啟逃逸分析,甚至在某些版本(如JDK 1.6 Update18)中還曾經(jīng)短暫地完全禁止了這項(xiàng)優(yōu)化弟塞。

6凭峡、對(duì)象回收

對(duì)象存活的判定

引用計(jì)數(shù)法:存在循環(huán)引用問(wèn)題。

Root搜索法(采用)

以下對(duì)象會(huì)被認(rèn)為是root對(duì)象:

被啟動(dòng)類(lèi)(bootstrap加載器)加載的類(lèi)和創(chuàng)建的對(duì)象

jvm運(yùn)行時(shí)方法區(qū)類(lèi)靜態(tài)變量(static)引用的對(duì)象

jvm運(yùn)行時(shí)方法去常量池引用的對(duì)象

jvm當(dāng)前運(yùn)行線(xiàn)程中的虛擬機(jī)棧變量表引用的對(duì)象

本地方法棧中(jni)引用的對(duì)象

注:由于finalize方法只會(huì)被JVM調(diào)用一次决记。

public class FinalizerTest {

public static FinalizerTest object;

public void isAlive() {

System.out.println("I'm alive");

}

@Override

protected void finalize() throws Throwable {

super.finalize();

System.out.println("method finalize is running");

object = this;

}

public static void main(String[] args) throws Exception {

object = new FinalizerTest();

// 第一次執(zhí)行,finalize方法會(huì)自救

object = null;

System.gc();

Thread.sleep(500);

if (object != null) {

object.isAlive();

} else {

System.out.println("I'm dead");

}

// 第二次執(zhí)行倍踪,finalize方法已經(jīng)執(zhí)行過(guò)

object = null;

System.gc();

Thread.sleep(500);

if (object != null) {

object.isAlive();

} else {

System.out.println("I'm dead");

}

}

}

執(zhí)行結(jié)果:

method finalize is running

I'm alive

I'm dead


方法區(qū)的回收主要包括兩部分內(nèi)容:廢棄常量和無(wú)用的類(lèi)系宫。

廢棄常量的回收與回收J(rèn)ava堆中的對(duì)象類(lèi)似。

判斷無(wú)用的類(lèi)的條件必須滿(mǎn)足三個(gè)條件:

該類(lèi)所有實(shí)例已經(jīng)被回收建车。

加載該類(lèi)的ClassLoader已被回收扩借。

該類(lèi)對(duì)應(yīng)的java.lang.Class對(duì)象沒(méi)有在任何地方被引用,也無(wú)法通過(guò)反射訪(fǎng)問(wèn)該類(lèi)缤至。

謝謝以下分享

http://www.importnew.com/13493.html

http://caoyaojun1988-163-com.iteye.com/blog/1969853

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末潮罪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子领斥,更是在濱河造成了極大的恐慌嫉到,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件月洛,死亡現(xiàn)場(chǎng)離奇詭異何恶,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)嚼黔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)细层,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人唬涧,你說(shuō)我怎么就攤上這事疫赎。” “怎么了碎节?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵捧搞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我钓株,道長(zhǎng)实牡,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任轴合,我火速辦了婚禮创坞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘受葛。我一直安慰自己题涨,他們只是感情好偎谁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著纲堵,像睡著了一般巡雨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上席函,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天铐望,我揣著相機(jī)與錄音,去河邊找鬼茂附。 笑死正蛙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的营曼。 我是一名探鬼主播乒验,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蒂阱!你這毒婦竟也來(lái)了锻全?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤录煤,失蹤者是張志新(化名)和其女友劉穎鳄厌,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體辐赞,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡部翘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了响委。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片新思。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖赘风,靈堂內(nèi)的尸體忽然破棺而出夹囚,到底是詐尸還是另有隱情,我是刑警寧澤邀窃,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布荸哟,位于F島的核電站,受9級(jí)特大地震影響瞬捕,放射性物質(zhì)發(fā)生泄漏鞍历。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一肪虎、第九天 我趴在偏房一處隱蔽的房頂上張望劣砍。 院中可真熱鬧,春花似錦扇救、人聲如沸刑枝。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)装畅。三九已至靠娱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掠兄,已是汗流浹背像云。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚂夕,地道東北人苫费。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像双抽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闲礼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • http://www.cnblogs.com/angeldevil/p/3801189.html值得一看 Clas...
    snail_knight閱讀 1,423評(píng)論 1 0
  • JVM架構(gòu) 當(dāng)一個(gè)程序啟動(dòng)之前牍汹,它的class會(huì)被類(lèi)裝載器裝入方法區(qū)(Permanent區(qū)),執(zhí)行引擎讀取方法區(qū)的...
    cocohaifang閱讀 1,664評(píng)論 0 7
  • 一 柬泽、java虛擬機(jī)底層結(jié)構(gòu)詳解 我們知道慎菲,一個(gè)JVM實(shí)例的行為不光是它自己的事,還涉及到它的子系統(tǒng)锨并、存儲(chǔ)區(qū)域露该、...
    葡萄喃喃囈語(yǔ)閱讀 1,484評(píng)論 0 4
  • 原文閱讀 前言 這段時(shí)間懈怠了,罪過(guò)第煮! 最近看到有同事也開(kāi)始用上了微信公眾號(hào)寫(xiě)博客了解幼,挺好的~給他們點(diǎn)贊,這博客我...
    碼農(nóng)戲碼閱讀 5,962評(píng)論 2 31
  • 刺穿我 刺穿我冰冷的身軀和蒼白的心臟 讓我隨你一并埋葬 拉住我 我還要繼續(xù)思念 別上了妝 卸了那些儀式上的假樣 走...
    顧晴梔閱讀 456評(píng)論 6 4