JVM Survivor行為一探究竟
MaxTenuringThreshold:
說到Survivor就不得不提及這個引數,笨神(微信公眾號:"你假笨", 想學習JVM調優的話,強烈推薦關注這個公眾號)昨天在JVM分享群裡分享了這個引數, 總結如下:
這個引數主要作用是設定在YGC的時候,新生代的物件正常情況下最多經過多少次YGC的過程會晉升到老生代,注意是表示最多而不是一定,也就是說某個物件的age其實並不是一定要達到這個值才會晉升到Old的,當你設定這個值的時候,第一次會以它為準,後面的就不一定以它為準了,而是JVM會自動計算在0~15之間決定,但不會超過這個值。如果配置了CMS GC,這個值預設是6;PS的話這個值預設是15。這個值最大你可以設定到15,因為jvm裡就4個bit來存這個值,所以最大就是1111,即15;
引申問題
那麼JVM是怎麼計算接下來S區的物件晉升到Old區的age的呢?介紹兩個重要的JVM引數:
-XX:TargetSurvivorRatio
一個計算期望S區存活大小(Desired survivor size)的引數. 預設引數為50,即50%。可參考JVMPocket。
PrintTenuringDistribution
輸出S區各個age的物件資訊, 用法:-XX:+PrintTenuringDistribution, -XX:-PrintTenuringDistribution
例如, gc日誌如下:
new threshold 1 (max 6)
- age 1: 1048608 bytes, 1048608 total
- age 2: 524304 bytes, 1572912 total
當一個S區中各個age的物件的總size大於或等於Desired survivor size ( TargetSurvivorRatio * S0 / 100 ),則重新計算age,以age和MaxTenuringThreshold兩者的最小值為準;驗證這個結論的Java程式碼如下:
public class GcSurvivorTest {
public static void main(String[] args) throws InterruptedException {
// 這兩個物件不會被回收, 用於在s0和s1不斷來回拷貝增加age直到達到PretenureSizeThreshold晉升到old
byte[] byte1m_1 = new byte[1 * 512 * 1024];
byte[] byte1m_2 = new byte[1 * 512 * 1024];
// YoungGC後, byte1m_1 和 byte1m_2的age為1
youngGc(1);
Thread.sleep(3000);
// 再次YoungGC後, byte1m_1 和 byte1m_2的age為2
youngGc(1);
Thread.sleep(3000);
// 第三次YoungGC後, byte1m_1 和 byte1m_2的age為3
youngGc(1);
Thread.sleep(3000);
// 這次再ygc時, 由於byte1m_1和byte1m_2的年齡已經是3,且MaxTenuringThreshold=3, 所以這兩個物件會晉升到Old區域,且ygc後, s0(from)和s1(to)空間中的物件被清空
youngGc(1);
Thread.sleep(3000);
// main方法中分配的物件不會被回收, 不斷分配是為了達到TargetSurvivorRatio這個比例指定的值, 即5M*60%=3M(Desired survivor size),說明: 5M為S區的大小,60%為TargetSurvivorRatio引數指定,如下三個物件分配後就能夠達到Desired survivor size
byte[] byte1m_4 = new byte[1 * 1024 * 1024];
byte[] byte1m_5 = new byte[1 * 1024 * 1024];
byte[] byte1m_6 = new byte[1 * 1024 * 1024];
// 這次ygc時, 由於s區已經佔用達到了60%(-XX:TargetSurvivorRatio=60), 所以會重新計算物件晉升的age,計算公式為:min(age, MaxTenuringThreshold) = 1
youngGc(1);
Thread.sleep(3000);
// 由於前一次ygc時算出age=1, 所以這一次再ygc時, byte1m_4, byte1m_5, byte1m_6就會晉升到Old區, 而不需要等MaxTenuringThreshold這麼多次, 此次ygc後, s0(from)和s1(to)空間中物件再次被清空, 物件全部晉升到old
youngGc(1);
Thread.sleep(3000);
System.out.println("hello world");
}
private static void youngGc(int ygcTimes){
for(int i=0; i<ygcTimes*40; i++) {
byte[] byte1m = new byte[1 * 1024 * 1024];
}
}
}
程式碼配套的JVM引數(Eden: 40M, S0/S1: 5M, Old: 150M):
-verbose:gc -Xmx200M -Xmn50M -XX:TargetSurvivorRatio=60 -XX:+PrintTenuringDistribution -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:MaxTenuringThreshold=3
由於JVM引數申明瞭-verbose:gc, 所以直接可以通過控制檯輸出gc日誌資訊驗證上面的結論,gc日誌如下:
2017-07-22T16:23:48.792+0800: [GC (Allocation Failure) 2017-07-22T16:23:48.792+0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
- age 1: 1643904 bytes, 1643904 total
: 40448K->1613K(46080K), 0.0016580 secs] 40448K->1613K(123904K), 0.0029600 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
2017-07-22T16:23:51.802+0800: [GC (Allocation Failure) 2017-07-22T16:23:51.802+0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
- age 2: 1640840 bytes, 1640840 total
: 42335K->1878K(46080K), 0.0020202 secs] 42335K->1878K(123904K), 0.0020925 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2017-07-22T16:23:54.812+0800: [GC (Allocation Failure) 2017-07-22T16:23:54.812+0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
- age 3: 1640536 bytes, 1640536 total
: 41990K->1777K(46080K), 0.0017066 secs] 41990K->1777K(123904K), 0.0017903 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2017-07-22T16:23:57.821+0800: [GC (Allocation Failure) 2017-07-22T16:23:57.821+0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
: 42504K->0K(46080K), 0.0056289 secs] 42504K->1651K(123904K), 0.0057150 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
2017-07-22T16:24:00.833+0800: [GC (Allocation Failure) 2017-07-22T16:24:00.833+0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 1 (max 3)
- age 1: 3145776 bytes, 3145776 total
: 40731K->3072K(46080K), 0.0023655 secs] 42382K->4723K(123904K), 0.0024508 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2017-07-22T16:24:03.843+0800: [GC (Allocation Failure) 2017-07-22T16:24:03.843+0800: [ParNew
Desired survivor size 3145728 bytes, new threshold 3 (max 3)
: 43806K->0K(46080K), 0.0034668 secs] 45457K->4723K(123904K), 0.0035526 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
hello world
Heap
par new generation total 46080K, used 15955K [0x00000000f3800000, 0x00000000f6a00000, 0x00000000f6a00000)
eden space 40960K, 38% used [0x00000000f3800000, 0x00000000f4794e90, 0x00000000f6000000)
from space 5120K, 0% used [0x00000000f6000000, 0x00000000f6000000, 0x00000000f6500000)
to space 5120K, 0% used [0x00000000f6500000, 0x00000000f6500000, 0x00000000f6a00000)
concurrent mark-sweep generation total 77824K, used 4723K [0x00000000f6a00000, 0x00000000fb600000, 0x0000000100000000)
Metaspace used 2840K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 305K, capacity 386K, committed 512K, reserved 1048576K
相關文章
- 深入理解JVM——(三)為什麼JVM新生代需要兩個Survivor區JVM
- JVM(六)為什麼新生代有兩個Survivor分割槽?JVM
- 【一探究竟】Flutter到底是什麼?Flutter
- 小米智慧家居進展如何?來一探究竟
- 避免用Apache Beanutils進行屬性的copy。why?讓我們一起一探究竟ApacheBean
- 2022遊戲出海有哪些風向標?這個大會將為你一探究竟遊戲
- JVM中的執行緒行為JVM執行緒
- 星環科技線上分享課“星課堂”開播,快來一探究竟
- 資料中心從何而來?華為雲學院帶你一探究竟!
- Google Play 獨立遊戲專區加入神祕板塊,快來一探究竟Go遊戲
- JVM原始碼分析之一個Java程式究竟能建立多少執行緒JVM原始碼Java執行緒
- Promise物件,究竟為何物?Promise物件
- 併發王者課-青銅5:一探究竟-如何從synchronized理解Java物件頭中的鎖synchronizedJava物件
- IT行業究竟有多吃香?行業
- 智慧廁所廁位引導系統怎麼建?中期科技zontree智慧公廁一探究竟
- 【JVM】JVM系列之執行引擎(五)JVM
- 華為雲分散式快取服務 DCS,它與開源 Redis 有哪些差異,快來一探究竟!分散式快取Redis
- 國產資料庫未來如何發展?2020中國資料庫技術大會一探究竟資料庫
- 為什麼 JVM 需要 GCJVMGC
- BEAM和JVM虛擬機器對比:JVM是為並行而構建的,而BEAM是為併發構建的 | ErlangJVM虛擬機並行
- 2022春節賀歲檔電影開分,水門橋不理想,四海崩了!用Python一探究竟Python
- 【隨筆】JVM核心:JVM執行和類載入JVM
- 執行緒崩潰為什麼不會導致 JVM 崩潰執行緒JVM
- 一探 koa-session 原始碼Session原始碼
- 一副AI耳機賣1200元?端側AI大模型+硬體= ?這場論壇帶你一探究竟AI大模型
- 來自100多個國家開發程式設計師票選了最喜歡的程式語言,來一探究竟!程式設計師
- 一探全棧專案真面目全棧
- JVM核心之JVM執行和類載入全過程JVM
- AI語音行業緊缺,成為全棧語音工程師究竟有多難?AI行業全棧工程師
- JVM執行時資料區JVM
- JVM 的執行子系統JVM
- 深入分析JVM執行引擎JVM
- 想成為電競專案的遊戲,究竟要走多少步?遊戲
- 今天,我們來探一探WebSocket原理Web
- 探一探快應用的虛實
- JVM 進行執行緒同步背後的原理JVM執行緒
- 從零開始JVM(一):初探JVM執行時資料區域JVM
- JVM執行時資料區域JVM