四辜限、java對(duì)象從new-內(nèi)存分配-GC流程

對(duì)象的創(chuàng)建:

image.png

1.類加載檢查

虛擬機(jī)字節(jié)碼執(zhí)行引擎執(zhí)行jvm指令如果為new時(shí)皇拣,會(huì)查看方法區(qū)中常量池該類的符號(hào)引用,查看符號(hào)引用的類信息是否存在薄嫡,如果不存在氧急,則執(zhí)行類加載過(guò)程。

2.加載類

執(zhí)行類加載機(jī)制岂座,通過(guò)雙親委派機(jī)制态蒂,使用類加載器加載類文件,驗(yàn)證字節(jié)碼文件的完整性费什,將類中的靜態(tài)變量賦值為初始值,將字面量的符號(hào)引用轉(zhuǎn)換成直接引用手素,初始化賦值靜態(tài)成員變量鸳址。

3.分配內(nèi)存

分三種情況: 1.直接分配到old區(qū)(老年代) 2.分配到Eden區(qū) 3.分配在線程本地緩存區(qū) 分配內(nèi)存的方式: 1.指針碰撞(默認(rèn)使用)java堆中的內(nèi)存規(guī)整的情況下,會(huì)將用過(guò)的內(nèi)存和沒(méi)用過(guò)的內(nèi)存分開放置泉懦,將加載后計(jì)算好的類的大小稿黍,挪動(dòng)類的大小的指針; 2.不規(guī)整的情況下 空閑列表(Free List) 如果內(nèi)存為不規(guī)整的情況下崩哩,虛擬機(jī)就需要維護(hù)一個(gè)內(nèi)存可用的列表巡球,分配時(shí)從列表中查找,如果找到一塊可用的內(nèi)存邓嘹,進(jìn)行分配內(nèi)存酣栈,并更新列表的狀態(tài) 并發(fā)問(wèn)題: 1.cas+失敗重試: 在分配內(nèi)存時(shí)可能被其他線程搶占分配,虛擬機(jī)會(huì)采用CAS+失敗重試來(lái)保證內(nèi)存分配的同步和原子性; 2.TLAB(Thread Local Allocation Buffer)線程本地緩沖區(qū) 在Eden 區(qū)會(huì)給每個(gè)線程分配一塊小的內(nèi)存汹押,用來(lái)存儲(chǔ)對(duì)象矿筝,是線程非共享的,只能當(dāng)前線程訪問(wèn)棚贾,可使用--XX:+UseTLAB開啟窖维,但是默認(rèn)是開啟狀態(tài);-XX:TLABSize可指定大小

4.初始化

內(nèi)存分配后將對(duì)象實(shí)例變量初始化為初始值妙痹,例如int會(huì)初始為0铸史,String 會(huì)初始為null;保證變量可以不用賦值就可以進(jìn)行操作;

5.設(shè)置對(duì)象頭

類在初始化后怯伊,會(huì)給對(duì)象進(jìn)行設(shè)置琳轿,設(shè)置類的引用實(shí)例信息,還有在對(duì)象頭中設(shè)置對(duì)象的hash值,對(duì)象的GC年齡利赋,鎖信息等水评; 對(duì)象在內(nèi)存中的存儲(chǔ)分為三個(gè)部分: 1.對(duì)象頭 Object Header 對(duì)象頭中分為兩個(gè)部分,第一個(gè)為對(duì)象的運(yùn)行時(shí)數(shù)據(jù)媚送,包括對(duì)象的hashcode中燥,鎖的狀態(tài)信息,是否偏量鎖塘偎,對(duì)象被GC的分代年齡疗涉,第二個(gè)為類型指針,對(duì)類元信息的引用指針吟秩;(如果是數(shù)組對(duì)象的話咱扣,還有一個(gè)數(shù)組長(zhǎng)度的數(shù)據(jù)部分) 2.實(shí)例數(shù)據(jù) Instance Data 3.對(duì)象填充 Padding 個(gè)人理解:對(duì)象填充是優(yōu)化對(duì)象存取速度,假設(shè)對(duì)象占用3個(gè)字節(jié)涵防,會(huì)填充一個(gè)字節(jié)闹伪,改為為4個(gè)字節(jié),4個(gè)字節(jié)存儲(chǔ)起來(lái)速度是最優(yōu)的壮池; 指針壓縮: -XX:-UseCompressedOops 關(guān)閉指針壓縮偏瓤,1.6以后默認(rèn)開啟指針壓縮 32位系統(tǒng)一個(gè)對(duì)象指針占用的字節(jié)為4個(gè),而64位操作系占用的為8個(gè)字節(jié)椰憋,在移動(dòng)指針時(shí)性能較低厅克,所以采用指針壓縮方式,進(jìn)而減少GC的壓力橙依;

對(duì)象在內(nèi)存中的存儲(chǔ)結(jié)構(gòu)如下:

clipboard.png

對(duì)象的內(nèi)存分配


image1.png

1.對(duì)象在棧上分配機(jī)制

對(duì)象在分配內(nèi)存時(shí)证舟,如上圖所示,會(huì)先嘗試在棧上分配內(nèi)存窗骑,在分配之前女责,會(huì)有一個(gè)逃逸分析算法,他的作用呢也是優(yōu)化垃圾對(duì)象盡快進(jìn)入老年代的優(yōu)化慧域,大概邏輯為:判斷對(duì)象是否會(huì)被外部引用鲤竹,假設(shè)說(shuō)有如下方法: 方法1: public void createUser(){ User user = new User(); } 方法2: public User createUser(){ User user = new User(); return user; } 方法1中只是創(chuàng)建了User對(duì)象,并沒(méi)有對(duì)外返回User 對(duì)象昔榴,而方法2中將User返回了辛藻,調(diào)用方式時(shí),肯定外部會(huì)對(duì)該對(duì)象的引用互订;所以當(dāng)方式1執(zhí)行時(shí)吱肌,可能就會(huì)分配在棧中,方法執(zhí)行完 仰禽,對(duì)象就會(huì)被回收了氮墨,而方法二中會(huì)有返回值纺蛆,可能外部對(duì)它進(jìn)行引用,則不會(huì)向棧中分配规揪;jdk1.7以后默認(rèn)開啟逃逸分析桥氏; 全量替換: 當(dāng)對(duì)象在認(rèn)為在外部不會(huì)引用時(shí),進(jìn)一步分解時(shí)猛铅,虛擬機(jī)不會(huì)創(chuàng)建該對(duì)象字支,而是它的成員方法,變量分解為這個(gè)方法使用的成員變量奸忽,這樣就不會(huì)因?yàn)闂V袥](méi)有一塊連續(xù)的空間而無(wú)法分配內(nèi)存堕伪。 -XX:+EliminateAllocations jdk1.7以后默認(rèn)開啟全量替換;

2.tlab線程本地緩存區(qū)

如上圖栗菜,如果會(huì)被外部所引用的情況下欠雌,虛擬機(jī)會(huì)首先判斷是否為大對(duì)象,如果不是大對(duì)象的話疙筹,會(huì)嘗試在Eden區(qū)中線程獨(dú)有的一塊區(qū)域中分配富俄;

3.對(duì)象在Eden區(qū)分配機(jī)制

如果為大對(duì)象的話,會(huì)在Eden區(qū)進(jìn)行分配內(nèi)存腌歉,當(dāng)Eden區(qū)的內(nèi)存不足以存放該對(duì)象時(shí)蛙酪,會(huì)出發(fā)minorGC/youngGc 年輕代的GC。 GC分為兩種GC翘盖,一種是minorGC/youngGC,一種是majorGC/Full GC; minorGC負(fù)責(zé)對(duì)年輕代內(nèi)存區(qū)域進(jìn)行回收凹蜂; majorGC負(fù)責(zé)老年代內(nèi)存區(qū)域進(jìn)行回收馍驯;

4.老年代分配擔(dān)保機(jī)制

minorGC 后會(huì)計(jì)算老年代的內(nèi)存空間,如果設(shè)置了一個(gè)參數(shù)“-XX:-HandlePromotionFailure” 玛痊,會(huì)判斷之前minorGC后的平均內(nèi)存如果大于老年代汰瘫,如果大于的話會(huì)直接執(zhí)行一次majorGC/Full GC,然后在執(zhí)行minorGC。

5.對(duì)象動(dòng)態(tài)年齡判斷

個(gè)人理解:動(dòng)態(tài)年齡判斷機(jī)制擂煞,也就是說(shuō)混弥,在Eden區(qū)和survivor1區(qū)域gc復(fù)制對(duì)象時(shí)中假設(shè)說(shuō)Survivor有三批對(duì)象,第一批對(duì)象占用10%对省,GC年齡為8蝗拿,第二批對(duì)象占20%,GC年齡也為8蒿涎,第三批 占用51%哀托,通過(guò)虛擬機(jī)參數(shù)-XX:TargetSurvivorRatio可配置大小劳秋;它就會(huì)把第一批和第二批對(duì)象放進(jìn)老年代仓手;這個(gè)規(guī)則是想把對(duì)象盡早進(jìn)入老年代胖齐,也是對(duì)jvm垃圾回收的一個(gè)優(yōu)化;

6.大對(duì)象直接進(jìn)入老年代

虛擬機(jī)為了優(yōu)化垃圾回收嗽冒,大對(duì)象會(huì)直接被分配到老年代呀伙,有個(gè)虛擬機(jī)參數(shù)-XX:PretenureSizeThreshold 可設(shè)置對(duì)象大小標(biāo)準(zhǔn),如果超過(guò)這個(gè)標(biāo)準(zhǔn)會(huì)直接分配到老年代添坊,而不會(huì)存放到年輕代剿另,只針對(duì)于Serial和Parnew兩個(gè)收集器的情況下有效;什么是大對(duì)象帅腌,需要連續(xù)的一塊內(nèi)存驰弄,例如字符串和數(shù)組;

7.長(zhǎng)期存活的對(duì)象進(jìn)入老年代

虛擬機(jī)給每個(gè)對(duì)象都標(biāo)記了年齡速客,當(dāng)在Eden區(qū)被gc后可以放到survivor區(qū)戚篙,這個(gè)對(duì)象接下來(lái)每次gc都會(huì)年齡+1,直到達(dá)到闕值后就會(huì)被放到老年代,通過(guò)-XX:MaxTenuringThreshold參數(shù)可以設(shè)置對(duì)象可存活的年齡溺职。默認(rèn)為15歲岔擂,CMS收集器的闕值為6歲。

對(duì)象的內(nèi)存回收

1.引用計(jì)數(shù)器

這個(gè)算法是效率最高的浪耘,不過(guò)也有缺點(diǎn)乱灵,他的原理是,給對(duì)象添加一個(gè)計(jì)數(shù)器七冲,每有一個(gè)引用就會(huì)計(jì)數(shù)器+1痛倚,如果釋放了引用,就會(huì)-1澜躺;如果已經(jīng)沒(méi)有被引用后蝉稳,他的計(jì)數(shù)器就會(huì)為0,就會(huì)被gc掉掘鄙,可以又有這么一個(gè)問(wèn)題: 有這么一段代碼:思考 user1 和 user2 是否計(jì)數(shù)器會(huì)變?yōu)?耘戚; User user1 = new User(); User user2 = new User(); user1.property = user2; user2.property = user1; user 1 = null; user2 = null; user1 和user2的計(jì)數(shù)器是不會(huì)變?yōu)?的,以為他們相互引用操漠;所以說(shuō)基本上這個(gè)算法不會(huì)用上收津;

2.可達(dá)性分析算法

理解這么一個(gè)概念GC Root ,什么是GC Root,可以理解為祖宗浊伙,他是最高級(jí)別的對(duì)象撞秋,這個(gè)算法的原理就是,在執(zhí)行g(shù)c時(shí)吧黄,會(huì)掃描部服,棧中的對(duì)象,類的靜態(tài)變量拗慨,本地方法棧廓八, 從GC Root開始查找引用的對(duì)象奉芦,如果有對(duì)該對(duì)象的引用,該GC Root就不會(huì)被標(biāo)記為垃圾對(duì)象剧蹂,其他的都會(huì)被標(biāo)記為垃圾對(duì)象声功,等待被垃圾收集器所回收。如下圖所示:


image2.png

擴(kuò)充:

如何判斷是一個(gè)無(wú)用的類

方法區(qū)主要回收無(wú)用的類分為三種:

1.堆中的對(duì)象已經(jīng)被回收掉了
2.加載該類的classloader已經(jīng)被回收了 
3.該類的java.lang.Class 對(duì)象已經(jīng)沒(méi)有存在引用關(guān)系宠叼,并且沒(méi)有用反射獲取方法和字段
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末先巴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子冒冬,更是在濱河造成了極大的恐慌伸蚯,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件简烤,死亡現(xiàn)場(chǎng)離奇詭異剂邮,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)横侦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門挥萌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人枉侧,你說(shuō)我怎么就攤上這事引瀑。” “怎么了榨馁?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵憨栽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我翼虫,道長(zhǎng)徒像,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任蛙讥,我火速辦了婚禮,結(jié)果婚禮上灭衷,老公的妹妹穿的比我還像新娘次慢。我一直安慰自己,他們只是感情好翔曲,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布迫像。 她就那樣靜靜地躺著,像睡著了一般瞳遍。 火紅的嫁衣襯著肌膚如雪闻妓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天掠械,我揣著相機(jī)與錄音由缆,去河邊找鬼注祖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛均唉,可吹牛的內(nèi)容都是我干的是晨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼舔箭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼罩缴!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起层扶,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤箫章,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后镜会,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體檬寂,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年稚叹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了焰薄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扒袖,死狀恐怖塞茅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情季率,我是刑警寧澤野瘦,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站飒泻,受9級(jí)特大地震影響鞭光,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泞遗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一惰许、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧史辙,春花似錦汹买、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至耙蔑,卻和暖如春见妒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背甸陌。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工须揣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盐股,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓返敬,卻偏偏與公主長(zhǎng)得像遂庄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子劲赠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345