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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容