自适应堆大小

一次性咖啡杯 在改进我们的测试平台以改进Plumbr GC问题检测器的同时 ,我最终编写了一个小型测试用例,我认为这对于更广泛的读者来说可能很有趣。 我追求的目标是测试JVM在eden,survivor和Tenured空间之间如何分割堆方面的自适应性。

测试本身正在成批生成对象。 批处理每秒生成一次,每个批处理大小为500KB。 这些对象被引用五秒钟,此后将删除引用,并且该特定批处理中的对象可以进行垃圾收集。

该测试是使用ParallelGC在Mac OS X上的Oracle Hotspot 7 JVM上运行的,具有30MB的可用堆空间。 了解了平台,我们可以预期JVM将使用以下堆配置启动:

  • JVM将以Young中的10MB和Tenured空间中的20MB开头,因为没有显式配置,JVM将使用1:2的比率在Young和Tenured空间之间分配堆。
  • 在我的Mac OS X中,在Eden和两个Survivor空间之间进一步分配了10MB的年轻空间,分别为8MB和2x1MB。 同样,这些是所使用的特定于平台的默认值。

的确,当启动测试并使用jstat在后台进行窥视时,我们将看到以下内容,这证实了我们的餐巾纸估计:

My Precious:gc-pressure me$ jstat -gc 2533 1s
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
1024.0 1024.0  0.0    0.0    8192.0   5154.4   20480.0      0.0     21504.0 2718.9      0    0.000   0      0.000    0.000
1024.0 1024.0  0.0    0.0    8192.0   5502.1   20480.0      0.0     21504.0 2720.1      0    0.000   0      0.000    0.000
1024.0 1024.0  0.0    0.0    8192.0   6197.5   20480.0      0.0     21504.0 2721.0      0    0.000   0      0.000    0.000
1024.0 1024.0  0.0    0.0    8192.0   6545.2   20480.0      0.0     21504.0 2721.2      0    0.000   0      0.000    0.000
1024.0 1024.0  0.0    0.0    8192.0   7066.8   20480.0      0.0     21504.0 2721.6      0    0.000   0      0.000    0.000
1024.0 1024.0  0.0    0.0    8192.0   7588.3   20480.0      0.0     21504.0 2722.1      0    0.000   0      0.000    0.000

从这里,我们还可以对即将发生的情况给出下一组预测:

  • 伊甸园中的8MB内存将在16秒内填满-请记住,我们每秒生成500KB的对象
  • 在每一刻,我们都有大约2.5MB的活动对象-每秒生成500KB,并将对象的引用保持五秒钟,这大约等于我们的数量
  • 每当Eden满时,次要GC都会触发-这意味着我们应该每16秒左右看到一次次要GC。
  • 在进行次要的GC之后,我们将过早地进行升级– Survivor空间只有1MB大小,而2.5MB的现场设置将无法容纳我们的1MB Survivor空间中的任何一个。 因此,清洁伊甸园的唯一方法是将1.5MB(2.5MB-1MB)的不适合生存者的活动物体传播到终身空间。

查看日志也使我们对这些预测充满信心:

My Precious:gc-pressure me$ jstat -gc -t 2575 1s
Time   S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
  6.6 1024.0 1024.0  0.0    0.0    8192.0   4117.9   20480.0      0.0     21504.0 2718.4      0    0.000   0      0.000    0.000
  7.6 1024.0 1024.0  0.0    0.0    8192.0   4639.4   20480.0      0.0     21504.0 2718.7      0    0.000   0      0.000    0.000
	... cut for brevity ...
 14.7 1024.0 1024.0  0.0    0.0    8192.0   8192.0   20480.0      0.0     21504.0 2723.6      0    0.000   0      0.000    0.000
 15.6 1024.0 1024.0  0.0   1008.0  8192.0   963.4    20480.0     1858.7   21504.0 2726.5      1    0.003   0      0.000    0.003
 16.7 1024.0 1024.0  0.0   1008.0  8192.0   1475.6   20480.0     1858.7   21504.0 2728.4      1    0.003   0      0.000    0.003
	... cut for brevity ...
 29.7 1024.0 1024.0  0.0   1008.0  8192.0   8163.4   20480.0     1858.7   21504.0 2732.3      1    0.003   0      0.000    0.003
 30.7 1024.0 1024.0 1008.0  0.0    8192.0   343.3    20480.0     3541.3   21504.0 2733.0      2    0.005   0      0.000    0.005
 31.8 1024.0 1024.0 1008.0  0.0    8192.0   952.1    20480.0     3541.3   21504.0 2733.0      2    0.005   0      0.000    0.005
	... cut for brevity ...
 45.8 1024.0 1024.0 1008.0  0.0    8192.0   8013.5   20480.0     3541.3   21504.0 2745.5      2    0.005   0      0.000    0.005
 46.8 1024.0 1024.0  0.0   1024.0  8192.0   413.4    20480.0     5201.9   21504.0 2745.5      3    0.008   0      0.000    0.008
 47.8 1024.0 1024.0  0.0   1024.0  8192.0   961.3    20480.0     5201.9   21504.0 2745.5      3    0.008   0      0.000    0.008

不是在16秒内,而是每15秒左右,垃圾收集就会启动,清理Eden,并将约1MB的活动对象传播到其中一个Survivor空间,并将剩余空间溢出到Old space。

到目前为止,一切都很好。 JVM确实表现出我们所期望的方式。 JVM监视了一段时间之后,有趣的部分开始了,并开始了解正在发生的事情。 在我们的测试案例中,这大约在90秒内发生:

My Precious:gc-pressure me$ jstat -gc -t 2575 1s
Time   S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
 94.0 1024.0 1024.0  0.0   1024.0  8192.0   8036.8   20480.0     8497.0   21504.0 2748.8      5    0.012   0      0.000    0.012
 95.0 1024.0 3072.0 1024.0  0.0    4096.0   353.3    20480.0    10149.6   21504.0 2748.8      6    0.014   0      0.000    0.014
 96.0 1024.0 3072.0 1024.0  0.0    4096.0   836.6    20480.0    10149.6   21504.0 2748.8      6    0.014   0      0.000    0.014
 97.0 1024.0 3072.0 1024.0  0.0    4096.0   1350.0   20480.0    10149.6   21504.0 2748.8      6    0.014   0      0.000    0.014
 98.0 1024.0 3072.0 1024.0  0.0    4096.0   1883.5   20480.0    10149.6   21504.0 2748.8      6    0.014   0      0.000    0.014
 99.0 1024.0 3072.0 1024.0  0.0    4096.0   2366.8   20480.0    10149.6   21504.0 2748.8      6    0.014   0      0.000    0.014
100.0 1024.0 3072.0 1024.0  0.0    4096.0   2890.2   20480.0    10149.6   21504.0 2748.8      6    0.014   0      0.000    0.014
101.0 1024.0 3072.0 1024.0  0.0    4096.0   3383.7   20480.0    10149.6   21504.0 2748.8      6    0.014   0      0.000    0.014
102.0 1024.0 3072.0 1024.0  0.0    4096.0   3909.7   20480.0    10149.6   21504.0 2748.8      6    0.014   0      0.000    0.014
103.0 3072.0 3072.0  0.0   2720.0  4096.0   323.0    20480.0    10269.6   21504.0 2748.9      7    0.016   0      0.000    0.016

我们在这里看到的是JVM的惊人适应性。 在了解了应用程序的行为之后,JVM调整了幸存者空间的大小,使其足以容纳所有活动对象。 现在,Young空间的新配置为:

  • 伊甸园4MB
  • 幸存者空间各3MB

此后,GC频率增加–伊甸园现在减小了50%,而不是大约16秒,它现在大约填充了8秒左右。 但是好处也显而易见,因为幸存者空间现在足够大,可以在任何给定时间容纳活动物。 再加上没有对象的生存时间超过一个较小的GC周期(请记住,在任何给定时间只有2.5MB的生存对象),我们便停止将对象提升到旧空间。

继续监视JVM,我们发现采用后旧空间使用率是恒定的。 没有更多的对象传播到旧的对象,但是由于没有触发任何主要的GC,在适应发生之前设法传播的约10MB垃圾将永远存在于旧的空间中。

如果您确定自己在做什么,还可以选择“惊人的适应性”。 在JVM参数中指定-XX-UseAdaptiveSizingPolicy将指示JVM坚持在启动时给定的参数,而不是试图超越您。 谨慎使用此选项,现代JVM通常非常擅长为您预测合适的配置。

翻译自: https://www.javacodegeeks.com/2014/10/adaptive-heap-sizing.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值