JVM 對象分配過程

對象分配過程

  • 1)依據(jù)逃逸分析效览,判斷是否能棧上分配?
    • 如果可以刹孔,使用標量替換方式啡省,把對象分配到VM Stack中。如果 線程銷毀或方法調(diào)用結(jié)束后髓霞,自動銷毀卦睹,不需要 GC 回收器 介入。
    • 否則方库,繼續(xù)下一步结序。
  • 2)判斷是否大對象?
    • 如果是纵潦,直接分配到堆上 Old Generation 老年代上徐鹤。如果對象變?yōu)槔螅衫夏甏鶪C 收集器(比如 Parallel Old, CMS, G1)回收邀层。
    • 否則返敬,繼續(xù)下一步。
  • 3)判斷是否可以在 TLAB中分配寥院?
    • 如果是劲赠,在 TLAB中分配堆上Eden區(qū)。
    • 否則,在 TLAB外堆上的Eden區(qū)分配凛澎。

棧上分配

本質(zhì)上是JVM提供的一個優(yōu)化技術(shù)霹肝。

  • 基本思想:將線程私有的對象打散分配在棧 VM Stack
  • 優(yōu)點:
    • 可以在函數(shù)調(diào)用結(jié)束后自行銷毀對象,不需要垃圾回收器的介入塑煎,有效避免垃圾回收帶來的負面影響
    • 棧上分配速度快沫换,提高系統(tǒng)性能
  • 局限性:
    • 棧空間小轧叽,對于大對象無法實現(xiàn)棧上分配
  • 技術(shù)基礎: 逃逸分析苗沧、標量替換

什么是逃逸分析?

關(guān)于 Java 逃逸分析的定義:

逃逸分析(Escape Analysis)簡單來講就是炭晒,Java Hotspot 虛擬機可以分析新創(chuàng)建對象的使用范圍待逞,并決定是否在 Java 堆上分配內(nèi)存的一項技術(shù)。

逃逸分析的 JVM 參數(shù)如下:

  • 開啟逃逸分析:-XX:+DoEscapeAnalysis
  • 關(guān)閉逃逸分析:-XX:-DoEscapeAnalysis
  • 顯示分析結(jié)果:-XX:+PrintEscapeAnalysis

逃逸分析技術(shù)在 Java SE 6u23+ 開始支持网严,并默認設置為啟用狀態(tài)识樱,可以不用額外加這個參數(shù)。

逃逸分析優(yōu)化

針對上面第三點震束,當一個對象沒有逃逸時怜庸,可以得到以下幾個虛擬機的優(yōu)化。

1) 鎖消除

我們知道線程同步鎖是非常犧牲性能的垢村,當編譯器確定當前對象只有當前線程使用割疾,那么就會移除該對象的同步鎖。

例如嘉栓,StringBuffer 和 Vector 都是用 synchronized 修飾線程安全的宏榕,但大部分情況下,它們都只是在當前線程中用到侵佃,這樣編譯器就會優(yōu)化移除掉這些鎖操作麻昼。

鎖消除的 JVM 參數(shù)如下:

  • 開啟鎖消除:-XX:+EliminateLocks
  • 關(guān)閉鎖消除:-XX:-EliminateLocks

鎖消除在 JDK8 中都是默認開啟的,并且鎖消除都要建立在逃逸分析的基礎上馋辈。

2) 標量替換

首先要明白標量和聚合量抚芦,基礎類型和對象的引用可以理解為標量,它們不能被進一步分解迈螟。而能被進一步分解的量就是聚合量叉抡,比如:對象。

對象是聚合量答毫,它又可以被進一步分解成標量褥民,將其成員變量分解為分散的變量,這就叫做標量替換烙常。

這樣,如果一個對象沒有發(fā)生逃逸,那壓根就不用創(chuàng)建它蚕脏,只會在椪旄保或者寄存器上創(chuàng)建它用到的成員標量,節(jié)省了內(nèi)存空間驼鞭,也提升了應用程序性能秦驯。

標量替換的 JVM 參數(shù)如下:

  • 開啟標量替換:-XX:+EliminateAllocations
  • 關(guān)閉標量替換:-XX:-EliminateAllocations
  • 顯示標量替換詳情:-XX:+PrintEliminateAllocations

標量替換同樣在 JDK8 中都是默認開啟的,并且都要建立在逃逸分析的基礎上挣棕。

3) 棧上分配

當對象沒有發(fā)生逃逸時译隘,該對象就可以通過標量替換分解成成員標量分配在棧內(nèi)存中,和方法的生命周期一致洛心,隨著棧幀出棧時銷毀固耘,減少了 GC 壓力,提高了應用程序性能词身。

示例代碼

import java.time.Instant;
/**
 * 棧上分配厅目,依賴于逃逸分析和標量替換
 *
 * @author Sven Augustus
 */
public class TestTLAB {
  // private static User u;
  /**
   * 一個User對象的大小:markdown 8 + class pointer 4 + int 4 + string (oops) 4 + padding 4 = 24B <br> 如果分配 100_000_000 個法严,則需要
   * 2400_000_000 字節(jié)损敷, 約 2.24 GB。
   */
  static class User {
    private int id;
    private String name;

    public User(int id, String name) {
      this.id = id;
      this.name = name;
    }
  }

  private static void alloc() {
    User u = new User(1, "SvenAugustus");
    // u = new User(1, "SvenAugustus");
  }
  public static void main(String[] args) throws InterruptedException {
    long start = Instant.now().toEpochMilli();
    for (int i = 0; i < 100_000_000; i++) {
      alloc();
    }
    System.out.println(Instant.now().toEpochMilli() - start);
  }
}

上述代碼調(diào)用了1億次alloc()深啤,如果是分配到堆上拗馒,大概需要 2.2 GB的堆空間,如果堆空間小于該值溯街,必然會觸發(fā)GC诱桂。

使用如下VM參數(shù)運行,發(fā)現(xiàn)不會觸發(fā)GC:

-server -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:+EliminateAllocations

使用如下參數(shù)(任意一行)運行苫幢,會發(fā)現(xiàn)觸大量 GC:

//不使用逃逸分析
-server -Xmx15m -Xms15m -XX:+PrintGCDetails -XX:-UseTLAB -XX:-DoEscapeAnalysis -XX:+EliminateAllocations
//不使用標量替換
-server -Xmx15m -Xms15m -XX:+PrintGCDetails -XX:-UseTLAB -XX:+DoEscapeAnalysis -XX:-EliminateAllocations

TLAB 分配

TLAB访诱,全稱Thread Local Allocation Buffer, 即:線程本地分配緩存。這是一塊線程專用的內(nèi)存分配區(qū)域韩肝。

TLAB占用的是eden區(qū)的空間触菜。

在TLAB啟用的情況下(默認開啟),JVM會為每一個線程分配一塊TLAB區(qū)域哀峻。

為什么需要TLAB涡相?

這是為了加速對象的分配。

由于對象一般分配在堆上剩蟀,而堆是線程共用的催蝗,因此可能會有多個線程在堆上申請空間,而每一次的對象分配都必須線程同步育特,會使分配的效率下降丙号。

考慮到對象分配幾乎是Java中最常用的操作先朦,因此JVM使用了TLAB這樣的線程專有區(qū)域來避免多線程沖突,提高對象分配的效率犬缨。

  • 局限性: TLAB空間一般不會太大(占用eden區(qū))喳魏,所以大對象無法進行TLAB分配,只能直接分配到堆 Heap上怀薛。

大對象

大對象的 JVM 參數(shù)如下:

  • 大對象到底多大:-XX:PreTenureSizeThreshold=n
    (僅適用于 DefNew / ParNew新生代垃圾回收器 ) https://bugs.openjdk.java.net/browse/JDK-8050209
  • G1回收器的大對象判斷刺彩,則依據(jù)Region的大小(-XX:G1HeapRegionSize)來判斷枝恋,如果對象大于Region50%以上创倔,就判斷為大對象Humongous Object

by Sven Augustus https://my.oschina.net/langxSpirit

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焚碌,一起剝皮案震驚了整個濱河市畦攘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呐能,老刑警劉巖念搬,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異摆出,居然都是意外死亡朗徊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門偎漫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爷恳,“玉大人,你說我怎么就攤上這事象踊∥虑祝” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵杯矩,是天一觀的道長栈虚。 經(jīng)常有香客問我,道長史隆,這世上最難降的妖魔是什么魂务? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮泌射,結(jié)果婚禮上粘姜,老公的妹妹穿的比我還像新娘。我一直安慰自己熔酷,他們只是感情好孤紧,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拒秘,像睡著了一般号显。 火紅的嫁衣襯著肌膚如雪臭猜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天押蚤,我揣著相機與錄音获讳,去河邊找鬼。 笑死活喊,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的量愧。 我是一名探鬼主播钾菊,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼偎肃!你這毒婦竟也來了煞烫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤累颂,失蹤者是張志新(化名)和其女友劉穎滞详,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體紊馏,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡料饥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了朱监。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岸啡。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赫编,靈堂內(nèi)的尸體忽然破棺而出巡蘸,到底是詐尸還是另有隱情,我是刑警寧澤擂送,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布悦荒,位于F島的核電站,受9級特大地震影響嘹吨,放射性物質(zhì)發(fā)生泄漏搬味。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一躺苦、第九天 我趴在偏房一處隱蔽的房頂上張望身腻。 院中可真熱鬧,春花似錦匹厘、人聲如沸嘀趟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽她按。三九已至牛隅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酌泰,已是汗流浹背媒佣。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留陵刹,地道東北人默伍。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像衰琐,于是被迫代替她去往敵國和親也糊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348