java虛擬機(jī)創(chuàng)建對(duì)象優(yōu)化策略總結(jié)

java在內(nèi)存中創(chuàng)建對(duì)象流程示意圖

1.???編譯器通過(guò)逃逸分析,確定對(duì)象是在棧上分配還是在堆上分配。如果是在堆上分配,則執(zhí)行步驟2.

2.???如果tlab_top(TLAB起始內(nèi)存值) + size(對(duì)象大?。?lt;= tlab_end(TLAB終止內(nèi)存值),則在在TLAB上直接分配對(duì)象并增加tlab_top?的值,如果現(xiàn)有的TLAB不足以存放當(dāng)前對(duì)象執(zhí)行步驟3.

3.???重新申請(qǐng)一個(gè)TLAB,并再次嘗試存放當(dāng)前對(duì)象。如果放不下,則執(zhí)行步驟4.

4.???在Eden區(qū)加鎖(這個(gè)區(qū)是多線程共享的),如果eden_top(eden起始內(nèi)存值) + size(對(duì)象大?。?<= eden_end(eden終止內(nèi)存值)則將對(duì)象存放在Eden區(qū),增加eden_top?的值,如果Eden區(qū)不足以存放,則執(zhí)行步驟5.

5.???執(zhí)行一次Young GC(minor collection)。

6.???經(jīng)過(guò)Young GC之后,如果Eden區(qū)任然不足以存放當(dāng)前對(duì)象,則直接分配到老年代。

1.背景

java為對(duì)象選擇上圖所示的分配策略,其實(shí)是為了提升創(chuàng)建對(duì)象的速率和減輕垃圾回收負(fù)擔(dān)兩個(gè)方面考慮的。

一般而言,對(duì)象都是存放在java堆內(nèi)存中,但是我們知道,堆內(nèi)存是所有線程共享的存儲(chǔ)空間,所以在并發(fā)情況下,如果要保證線程安全,需要使用同步的方式進(jìn)行解決,這樣一來(lái)就嚴(yán)重拖慢了對(duì)象創(chuàng)建的速度。

為了解決這個(gè)問(wèn)題,就考慮采用如下兩種方式解決這個(gè)問(wèn)題:

第一種方式:棧上分配(棧是線程安全的)

棧上分配是java虛擬機(jī)提供的一種優(yōu)化技術(shù),基本思想是對(duì)于那些線程私有的對(duì)象(指的是不可能被其他線程訪問(wèn)的對(duì)象),可以將它們打散分配在棧上,而不是分配在堆上。分配在棧上的好處是可以在函數(shù)調(diào)用結(jié)束后自行銷毀,而不需要垃圾回收器的介入,從而提供系統(tǒng)的性能。

提示:棧上分配的一個(gè)技術(shù)基礎(chǔ)是需要對(duì)要生成的對(duì)象進(jìn)行逃逸分析

因?yàn)闂I系膶?duì)象是線程私有的,不存在共享問(wèn)題,所以需要進(jìn)行逃逸分析該對(duì)象是否符合棧上分配的條件;

逃逸分析:主要目的就是判斷對(duì)象的作用域是否有可能逃出函數(shù)體。在運(yùn)行的時(shí)候分析對(duì)象的生命周期,如果發(fā)現(xiàn)該對(duì)象只在本線程中使用,例如方法中的局部變量,在方法執(zhí)行完后,該對(duì)象的生命周期就結(jié)束的情況等,那么就將該對(duì)象在棧上分配,而不在堆(Heap)分配,以減少對(duì)象對(duì)堆的壓力,減少GC的次數(shù)。

第二種方式:TLAB(ThreadLocal Allocation Buffer)

如果創(chuàng)建對(duì)象的時(shí)候,該對(duì)象不滿足在棧上分配的條件,則只好向堆內(nèi)存申請(qǐng)空間,但是堆內(nèi)存是多線程共享的區(qū)域,如果對(duì)堆進(jìn)行同步策略,對(duì)系統(tǒng)的性能影響可想而知。

所以,JVM在內(nèi)存新生代Eden Space中開(kāi)辟了一小塊線程私有的區(qū)域,稱作TLAB(Thread-local allocation buffer)。默認(rèn)設(shè)定為占用Eden Space的1%。在Java程序中很多對(duì)象都是小對(duì)象且用過(guò)即丟,它們不存在線程共享也適合被快速GC,所以對(duì)于小對(duì)象通常JVM會(huì)優(yōu)先分配在TLAB上,并且TLAB上的分配由于是線程私有所以沒(méi)有鎖開(kāi)銷。因此在實(shí)踐中分配多個(gè)小對(duì)象的效率通常比分配一個(gè)大對(duì)象的效率要高。

也就是說(shuō),Java中每個(gè)線程都會(huì)有自己的緩沖區(qū)稱作TLAB(Thread-local allocation buffer),每個(gè)TLAB都只有一個(gè)線程可以操作,TLAB結(jié)合bump-the-pointer技術(shù)可以實(shí)現(xiàn)快速的對(duì)象分配,而不需要任何的鎖進(jìn)行同步,也就是說(shuō),在對(duì)象分配的時(shí)候不用鎖住整個(gè)堆,而只需要在自己的緩沖區(qū)分配即可。

提示:

這里有個(gè)地方容易產(chǎn)生誤導(dǎo)。

TLAB是JVM在堆上分配內(nèi)存的時(shí)候,為了減少加鎖操作而設(shè)計(jì)的一種優(yōu)化方案,TLAB中的對(duì)象仍然是多線程共享的;其根本目的就是為了加速內(nèi)存分配而設(shè)計(jì)的,而并非TLAB中的數(shù)據(jù),只能由其所對(duì)應(yīng)線程訪問(wèn)。

在HotSpot VM里,TLAB只有在“分配”這個(gè)動(dòng)作上是線程獨(dú)占的,而在使用/收集意義上都還是讓所有線程共享的;使用上的共享并不需要做任何額外檢查。

總結(jié):

對(duì)象不在堆上分配主要的原因還是堆是共享的,在堆上分配有鎖的開(kāi)銷。無(wú)論是TLAB還是棧都是線程私有的,私有即避免了競(jìng)爭(zhēng)的問(wèn)題,這是典型的用空間換時(shí)間的做法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容