Java對象分配流程java
是java虛擬機提供的一項優化技術,它的基本思想是,對於那些線程私有對象(指不可能被其餘線程訪問的對象)能夠將它們打散分配在棧上,而不是分配在堆上。緩存
好處: 分配在棧上能夠結束後自行銷燬,不須要垃圾回收器介入,從而提升系統的性能。性能優化
侷限性: 棧空間小,對於大對象沒法實現棧上分配。bash
基礎:棧上分配依賴於逃逸分析和標量替換。markdown
棧上分配的一個技術基礎是進行逃逸分析。目的是判斷對象的做用域是否有可能逃逸出逃逸體。多線程
虛擬機會進行逃逸分析,判斷線程內私有對象是否有可能被其餘線程訪問,致使逃逸,而後虛擬機就會根據是否可能會逃逸將其分配在棧上,或者堆中。函數
只有在server模式下,才能開啓逃逸分析。 以下示例: oop
代碼:性能
//user的做用域超出了函數setUser的範圍,是逃逸對象 //當函數結束調用時,不會自行銷燬user private User user; public void setUser(){ user = new User(); user.setId(1); user.setName("blueStarWei"); } //u只在函數內部生效,不是逃逸對象 //當函數調用結束,會自行銷燬對象u public void createUser(){ User u = new User(); u.setId(2); u.setName("JVM"); } 複製代碼
棧上示例分配:<來自實戰java虛擬機>優化
public class AllotOnStack { public static class{ public int id=0; public String name=""; } public static void main(String[] args) { long start = System.currentTimeMillis(); for (int i = 0; i < 100000000; i++) { alloc(); } long end = System.currentTimeMillis(); System.out.println(end - start); } private static void alloc() { User user = new User(); user.setId(1); user.setName("zengxinyao"); } } 複製代碼
上述代碼調用了1億次alloc(),若是是分配到堆上,大概須要1.5GB的堆空間,若是堆空間小於該值,必然會觸發GC。
使用以下參數運行,發現不會觸發GC
-server -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:+EliminateAllocations
複製代碼
使用以下參數(任意一行)運行,會發現觸大量GC
//不使用逃逸分析
-server -Xmx15m -Xms15m -XX:-DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:+EliminateAllocations
//不使用標量替換
-server -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:-EliminateAllocations
複製代碼
能夠得出: 棧上分配依賴於逃逸分析和標量替換
JVM參數解析
TLAB 分配
TLAB,全稱Thread Local Allocation Buffer,即:線程本地分配緩存。這是一塊線程專用的內存分配區域。TLAB佔用的是eden區的空間。在TLAB啓用的狀況下(默認開啓),JVM會爲每個線程分配一塊TLAB區域。
爲何須要TLAB?
這是爲了加速對象的分配。因爲對象通常分配在堆上,而堆是線程共用的,所以可能會有多個線程在堆上申請空間,而每一次的對象分配都必須線程同步,會使分配的效率降低。考慮到對象分配幾乎是Java中最經常使用的操做,所以JVM使用了TLAB這樣的線程專有區域來避免多線程衝突,提升對象分配的效率
侷限性:TLAB空間通常不會太大(佔用eden區),因此大對象沒法進行TLAB分配,只能直接分配到堆上.
分配策略:
一個100KB的TLAB區域,若是已經使用了80KB,當須要分配一個30KB的對象時,TLAB是如何分配的呢?
此時,虛擬機有兩種選擇:第一,廢棄當前的TLAB(會浪費20KB的空3.4 間);第二,將這個30KB的對象直接分配到堆上,保留當前TLAB(當有小於20KB的對象請求TLAB分配時能夠直接使用該TLAB區域)。
JVM選擇的策略是:在虛擬機內部維護一個叫refill_waste的值,當請求對象大於refill_waste時,會選擇在堆中分配,反之,則會廢棄當前TLAB,新建TLAB來分配新對象。
【默認狀況下,TLAB和refill_waste都是會在運行時不斷調整的,使系統的運行狀態達到最優。
取自: 《實戰Java虛擬機 - JVM故障診斷與性能優化》 棧上分配、TLAB : blog.csdn.net/yangsnow_ra…