jvm 優(yōu)化篇-(5)-線程局部緩存TLAB 指針碰撞、Eden區(qū)分配 -XX:+UseTLAB -XX:+PrintTLAB -XX:TLABWasteTargetPercent

告訴大家技術(shù)不枯燥

TLAB(Thread Local Allocation Buffer)

????線程本地分配緩存石窑,這是一個(gè)線程獨(dú)享的內(nèi)存分配區(qū)域尼斧。

特點(diǎn):
  • TLAB解決了:直接在線程共享堆上安全分配帶來的線程同步性能消耗問題(解決了指針碰撞)棺棵。
  • TLAB內(nèi)存空間位于Eden區(qū)烛恤。
  • 默認(rèn)TLAB大小為占用Eden Space的1%缚柏。
開啟TLAB的參數(shù):

-XX:+UseTLAB
-XX:+TLABSize
-XX:TLABRefillWasteFraction
-XX:TLABWasteTargetPercent
-XX:+PrintTLAB <<<<<傳送門

TLAB的數(shù)據(jù)結(jié)構(gòu):
class ThreadLocalAllocBuffer: public CHeapObj<mtThread> {
  HeapWord* _start;                              // address of TLAB
  HeapWord* _top;                                // address after last allocation
  HeapWord* _pf_top;                             // allocation prefetch watermark
  HeapWord* _end;                                // allocation end (excluding alignment_reserve)
  size_t    _desired_size;                       // desired size   (including alignment_reserve)
  size_t    _refill_waste_limit;                 // hold onto tlab if free() is larger than this
  .....................省略......................
}
  • _start 指TLAB連續(xù)內(nèi)存起始地址币喧。
  • _top 指TLAB當(dāng)前分配到的地址杀餐。
  • _end 指TLAB連續(xù)內(nèi)存截止地址史翘。
  • _desired_size 是指TLAB的內(nèi)存大小琼讽。
  • _refill_waste_limit 是指最大的浪費(fèi)空間钻蹬。默認(rèn)值為64b脉让,jdk1.8<<<<<傳送門
    • eg:假設(shè)為_refill_waste_limit=5KB:
      ????????1、假如當(dāng)前TLAB已經(jīng)分配96KB术唬,還剩下4KB可分配粗仓,但是現(xiàn)在new了一個(gè)對(duì)象需要6KB的空間借浊,顯然TLAB的內(nèi)存不夠了蚂斤,4kb<5kb這時(shí)只浪費(fèi)4KB的空間曙蒸,在_refill_waste_limit 之內(nèi)纽窟,這時(shí)可以申請(qǐng)一個(gè)新的TLAB空間臂港,原先的TLAB交給Eden管理审孽。
      ????????2、假如當(dāng)前TLAB已經(jīng)分配90KB显拳,還剩下10KB,現(xiàn)在new了一個(gè)對(duì)象需要11KB瘸洛,顯然TLAB的內(nèi)存不夠了反肋,這時(shí)就不能簡單的拋棄當(dāng)前TLAB,這11KB會(huì)被安排到Eden區(qū)進(jìn)行申請(qǐng)畅形。
分配規(guī)則:

????????1、obj_size + tlab_top <= tlab_end日熬,直接在TLAB空間分配對(duì)象。
????????2耘纱、obj_size + tlab_top >= tlab_end && tlab_free > tlab_refill_waste_limit毕荐,對(duì)象不在TLAB分配,在Eden區(qū)分配员寇。(tlab_free:剩余的內(nèi)存空間虽填,tlab_refill_waste_limit:允許浪費(fèi)的內(nèi)存空間)<----總結(jié):tlab剩余可用空間>tlab可浪費(fèi)空間,當(dāng)前線程不能丟棄當(dāng)前TLAB斋日,本次申請(qǐng)交由Eden區(qū)分配空間
????????3第献、????????obj_size + tlab_top >= tlab_end && tlab_free < _refill_waste_limit,重新分配一塊TLAB空間仔拟,在新的TLAB中分配對(duì)象飒赃。<----總結(jié):tlab剩余可用空間<tlab可浪費(fèi)空間,在當(dāng)前允許可浪費(fèi)空間內(nèi)炒事,重新申請(qǐng)一個(gè)新TLAB空間蔫慧,原TLAB交給Eden

清單:/src/share/vm/memory/ThreadLocalAllocationBuffer.inline.hpp
功能:TLAB內(nèi)存分配

inline HeapWord* ThreadLocalAllocBuffer::allocate(size_t size) {
  invariants();
  // 獲取當(dāng)前top
  HeapWord* obj = top();
  if (pointer_delta(end(), obj) >= size) {
    // successful thread-local allocation
#ifdef ASSERT
    // Skip mangling the space corresponding to the object header to
    // ensure that the returned space is not considered parsable by
    // any concurrent GC thread.
    size_t hdr_size = oopDesc::header_size();
    Copy::fill_to_words(obj + hdr_size, size - hdr_size, badHeapWordVal);
#endif // ASSERT
    // This addition is safe because we know that top is
    // at least size below end, so the add can't wrap.
    // 重置top
    set_top(obj + size);

    invariants();
    return obj;
  }
  return NULL;
}

??????實(shí)際上虛擬機(jī)內(nèi)部會(huì)維護(hù)一個(gè)叫作refill_waste的值睡扬,當(dāng)請(qǐng)求對(duì)象大于refill_waste時(shí)黍析,會(huì)選擇在堆中分配,若小于該值韧涨,則會(huì)廢棄當(dāng)前TLAB,新建TLAB來分配對(duì)象虑粥。這個(gè)閾值可以使用TLABRefillWasteFraction來調(diào)整宪哩,它表示TLAB中允許產(chǎn)生這種浪費(fèi)的比例。默認(rèn)值為64彬祖,即表示使用約為1/64的TLAB空間作為refill_waste品抽。默認(rèn)情況下,TLAB和refill_waste都會(huì)在運(yùn)行時(shí)不斷調(diào)整的圆恤,使系統(tǒng)的運(yùn)行狀態(tài)達(dá)到最優(yōu)。如果想要禁用自動(dòng)調(diào)整TLAB的大小,可以使用-XX:-ResizeTLAB禁用ResizeTLAB焊虏,并使用-XX:TLABSize手工指定一個(gè)TLAB的大小秕磷。

指針碰撞&Eden區(qū)分配
指針碰撞
               // 指針碰撞分配
              HeapWord* compare_to = *Universe::heap()->top_addr();
              HeapWord* new_top = compare_to + obj_size;
              if (new_top <= *Universe::heap()->end_addr()) {
                if (Atomic::cmpxchg_ptr(new_top, Universe::heap()->top_addr(), compare_to) != compare_to) {
                  goto retry;
                }
                result = (oop) compare_to;
              }
            }

Eden區(qū)指針碰撞澎嚣,需要模擬多線程并發(fā)申請(qǐng)內(nèi)存空間。且需要關(guān)閉逃逸分析 -XX:-DoEscapeAnalysis -XX:+UseTLAB


/**
 * @author biudefu
 * @since 2019/8/19  下午11:25
-Xmx100m -Xms100m -XX:-DoEscapeAnalysis -XX:+UseTLAB 
-XX:TLABWasteTargetPercent=1 -XX:+PrintCommandLineFlags  -XX:+PrintGCDetails
 */
public class AllocationTLABSomeThread {

    private static final int threadNum = 100;
    private static CountDownLatch latch = new CountDownLatch(threadNum);
    private static final int n = 50000000 / threadNum;

    private static void alloc() {
        byte[] b = new byte[100];
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < threadNum; i++) {
            new Thread(() -> {
                for (int j = 0; j < n; j++) {
                    alloc();
                }
                latch.countDown();
            }).start();
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            System.out.println("hello world");
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

}
運(yùn)行結(jié)果:
-XX:-DoEscapeAnalysis -XX:InitialHeapSize=104857600 -XX:MaxHeapSize=104857600 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:TLABWasteTargetPercent=1 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC -XX:+UseTLAB 
[GC (Allocation Failure) [PSYoungGen: 25600K->960K(29696K)] 25600K->968K(98304K), 0.0019559 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 26560K->960K(29696K)] 26568K->968K(98304K), 0.0022243 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 26560K->768K(29696K)] 26568K->776K(98304K), 0.0022446 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
........
[GC (Allocation Failure) [PSYoungGen: 32768K->0K(33280K)] 34193K->1425K(101888K), 0.0014598 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 32768K->0K(33280K)] 34193K->1425K(101888K), 0.0015168 secs] [Times: user=0.00 sys=0.01, real=0.00 secs] 
823
Heap
 PSYoungGen      total 33280K, used 3655K [0x00000007bdf00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 32768K, 11% used [0x00000007bdf00000,0x00000007be291c48,0x00000007bff00000)
  from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
  to   space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
 ParOldGen       total 68608K, used 1425K [0x00000007b9c00000, 0x00000007bdf00000, 0x00000007bdf00000)
  object space 68608K, 2% used [0x00000007b9c00000,0x00000007b9d64798,0x00000007bdf00000)
 Metaspace       used 4255K, capacity 4718K, committed 4992K, reserved 1056768K
  class space    used 477K, capacity 533K, committed 640K, reserved 1048576K

關(guān)閉逃逸和TLAB分配 -XX:-DoEscapeAnalysis -XX:-UseTLAB 運(yùn)行結(jié)果:

-XX:-DoEscapeAnalysis -XX:InitialHeapSize=104857600 -XX:MaxHeapSize=104857600 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:TLABWasteTargetPercent=1 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC -XX:-UseTLAB 
[GC (Allocation Failure) [PSYoungGen: 25599K->976K(29696K)] 25599K->984K(98304K), 0.0023516 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 26575K->880K(29696K)] 26583K->888K(98304K), 0.0015459 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 26480K->832K(29696K)] 26488K->840K(98304K), 0.0006776 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
.......
[GC (Allocation Failure) [PSYoungGen: 32767K->0K(33280K)] 34053K->1285K(101888K), 0.0004838 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 32767K->0K(33280K)] 34053K->1285K(101888K), 0.0005389 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
5388
Heap
 PSYoungGen      total 33280K, used 21392K [0x00000007bdf00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 32768K, 65% used [0x00000007bdf00000,0x00000007bf3e4230,0x00000007bff00000)
  from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
  to   space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
 ParOldGen       total 68608K, used 1285K [0x00000007b9c00000, 0x00000007bdf00000, 0x00000007bdf00000)
  object space 68608K, 1% used [0x00000007b9c00000,0x00000007b9d41788,0x00000007bdf00000)
 Metaspace       used 4248K, capacity 4718K, committed 4992K, reserved 1056768K
  class space    used 478K, capacity 533K, committed 640K, reserved 1048576K

經(jīng)過對(duì)比颈抚,相差7倍左右嚼鹉。二者內(nèi)存回收??,從YoungGC次數(shù)和耗時(shí)上沒有太大變化:應(yīng)為都是Eden區(qū)分配匹舞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末线脚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子姊舵,更是在濱河造成了極大的恐慌寓落,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件史飞,死亡現(xiàn)場離奇詭異仰税,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)陨簇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拦赠,“玉大人,你說我怎么就攤上這事句携≡世郑” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蠢笋,是天一觀的道長鳞陨。 經(jīng)常有香客問我,道長厦滤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任享怀,我火速辦了婚禮趟咆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鳞贷。我一直安慰自己计雌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布妈橄。 她就那樣靜靜地躺著翁脆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪反番。 梳的紋絲不亂的頭發(fā)上叉钥,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天投队,我揣著相機(jī)與錄音爵川,去河邊找鬼敷鸦。 笑死寝贡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碟案。 我是一名探鬼主播颇蜡,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼熔任!你這毒婦竟也來了唁情?” 一聲冷哼從身側(cè)響起甫匹,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抢韭,沒想到半個(gè)月后恍箭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鳍贾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年交洗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咆爽。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖符糊,靈堂內(nèi)的尸體忽然破棺而出呛凶,到底是詐尸還是另有隱情男娄,我是刑警寧澤把兔,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布县好,位于F島的核電站,受9級(jí)特大地震影響缕贡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜收擦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一谍倦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昼蛀,春花似錦、人聲如沸仇哆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽延欠。三九已至阐斜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谒出,已是汗流浹背邻奠。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國打工为居, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贰镣。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓膳凝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親上煤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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

  • 簡書 占小狼轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝永部! 背景 介紹TLAB之前先思考一個(gè)問題:創(chuàng)建對(duì)象時(shí),需要在堆上申請(qǐng)指定大小的...
    美團(tuán)Java閱讀 14,421評(píng)論 18 64
  • TLAB整理 HotSpot VM在JAVA堆中對(duì)象創(chuàng)建,布局,訪問全過程(僅限于普通java對(duì)象,不包括數(shù)組和C...
    andersonoy閱讀 3,040評(píng)論 0 2
  • 我們?cè)趯W(xué)習(xí)使用Java的過程中,一般認(rèn)為new出來的對(duì)象都是被分配在堆上组橄,但是這個(gè)結(jié)論不是那么的絕對(duì),通過對(duì)Jav...
    新時(shí)代農(nóng)民工閱讀 375評(píng)論 0 1
  • 特點(diǎn) Java 堆(Java Heap)是 Java 虛擬機(jī)所管理的內(nèi)存中最大的一塊,也被稱為 “GC堆”毫炉,是被所...
    _曉__閱讀 2,649評(píng)論 2 9
  • 轉(zhuǎn)載blog.csdn.net/ning109314/article/details/10411495/ JVM工...
    forever_smile閱讀 5,366評(píng)論 1 56