[讨论] 实时数据处理的gc调优建议?

chosen0ne 2011-11-10
公司的一个项目主要是做实时数据处理,最近发现gc频繁,换用各种收集器,情况都不是很理想。
    使用parallel gc: young gc每5-7s执行一次,每次0.2ms,full gc要3-5m执行一次, 每次要可怕的2s。
    换用CMS: young gc要3s执行一次,每次不到0.1s,full gc执行的频率很高,1-2m执行一次,每次0.5s。
    不知道具体原因是什么,我想问一下大牛们,对于这种实时数据处理的程序,具体的gc调优方法有哪些?

    应用场景:每5s接收客户端发送的2MB左右的json数据,然后解析json,转化成大概2000+的map,放入队列中,多线程取出map进行处理、写入数据库(生产者-消费者模式)。

    我觉得,理想情况下,接收json数据到转化为map再到处理完成就只在新生代,然后老年代只存放一些缓存数据,这样在处理完这5s的数据后触发一次young gc,只需要少量的复制就可以完成(大部分对象都是过期的。。)。这样就要调大新生代的大小,以存放这5s产生的对象。老年代就只要设置的比所有缓存稍微大一点就ok了(大概需要200M的空间用于缓存)。

    不知道这个思路对不对?有没有什么更好的方法?
   
    十分感谢!!!

   
blueswind8306 2011-11-11
既然是5s执行一次,可以考虑将此应用放进crontab定时触发,而不是程序内部的Timer触发(如果缓存数据比较多,可以考虑把缓存单独放memcached或者其它进程,然后做进程间通讯),调大新生代。每次crontab启动后生成标志文件,结束前删除标志文件,下次根据标志文件判断是否需要启动。这样的目的是每次启动的应用都是新分配的堆内存,而只要保证每次应用的生命期内所分配的总内存小于Eden就可以做到还来不及MinorGC进程就结束了。
hittyt 2011-11-13
能不能给出你JVM的具体启动参数呢?
有些场景,比如:你在Young Gen里面的活着的对象太多,导致在进行Minor GC时在一个S区没法装下所有活着的对象时,就会造成那些活着的对象直接晋级Old Gen。
从你的描述来看,如果你的应用真的是这种情况的话,因为你的Minor GC非常频繁,就会造成Old Gen在每次Minor GC的同时跟着疯长。大到你设置的某个阈值的时候,就该Full GC了。
当然这只是一种可能,至于是不是真的是这样,还要看你的JVM数据了。
chosen0ne 2011-11-14
blueswind8306 写道
既然是5s执行一次,可以考虑将此应用放进crontab定时触发,而不是程序内部的Timer触发(如果缓存数据比较多,可以考虑把缓存单独放memcached或者其它进程,然后做进程间通讯),调大新生代。每次crontab启动后生成标志文件,结束前删除标志文件,下次根据标志文件判断是否需要启动。这样的目的是每次启动的应用都是新分配的堆内存,而只要保证每次应用的生命期内所分配的总内存小于Eden就可以做到还来不及MinorGC进程就结束了。


我没有描述清楚,这个应用是一直运行的,然后客户端也就是发送程序大概每5s发送一次数据。不过用crontab这个方案,跟我设想的能够在处理完所有数据后执行一次minor gc很相似。是不是只有调大新生代恰好能够容下一批数据,就会达到这个目的?
chosen0ne 2011-11-14
hittyt 写道
能不能给出你JVM的具体启动参数呢?
有些场景,比如:你在Young Gen里面的活着的对象太多,导致在进行Minor GC时在一个S区没法装下所有活着的对象时,就会造成那些活着的对象直接晋级Old Gen。
从你的描述来看,如果你的应用真的是这种情况的话,因为你的Minor GC非常频繁,就会造成Old Gen在每次Minor GC的同时跟着疯长。大到你设置的某个阈值的时候,就该Full GC了。
当然这只是一种可能,至于是不是真的是这样,还要看你的JVM数据了。


jstat -gc 1s钟打印一次:
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
58240.0 58240.0 58223.7  0.0   932096.0 735475.9  487424.0   299461.2  29760.0 29494.7   1732  356.083  171   283.755  639.837
58240.0 58240.0 58223.7  0.0   932096.0 735477.9  487424.0   299461.2  29760.0 29494.7   1732  356.083  171   283.755  639.837
58240.0 58240.0 58223.7  0.0   932096.0 872747.2  487424.0   299461.2  29760.0 29494.7   1732  356.083  171   283.755  639.837
58240.0 58240.0 58223.7  0.0   932096.0 930165.6  487424.0   299461.2  29760.0 29494.7   1732  356.083  171   283.755  639.837
58240.0 58240.0  0.0   36107.7 932096.0   0.0     487424.0   330175.0  29760.0 29494.7   1733  356.274  171   283.755  640.029
58240.0 58240.0  0.0   36107.7 932096.0 185536.2  487424.0   330175.0  29760.0 29494.7   1733  356.274  171   283.755  640.029
58240.0 58240.0  0.0   36107.7 932096.0 210916.1  487424.0   330175.0  29760.0 29494.7   1733  356.274  171   283.755  640.029
58240.0 58240.0  0.0   36107.7 932096.0 338855.3  487424.0   330175.0  29760.0 29494.7   1733  356.274  171   283.755  640.029
58240.0 58240.0  0.0   36107.7 932096.0 404110.6  487424.0   330175.0  29760.0 29494.7   1733  356.274  171   283.755  640.029
58240.0 58240.0  0.0   36107.7 932096.0 404123.8  487424.0   330175.0  29760.0 29494.7   1733  356.274  171   283.755  640.029


gc日志:
318132.430: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 932096K->45513K(990336K)] 1135714K->249131K(1477760K), 0.1389430 secs] [Times: user=0.54 sys=0.00, real=0.13 secs]
318144.446: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 977609K->56458K(990336K)] 1181227K->290015K(1477760K), 0.2209460 secs] [Times: user=0.87 sys=0.00, real=0.22 secs]
318157.401: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 988554K->58240K(990336K)] 1222111K->326197K(1477760K), 0.3276150 secs] [Times: user=0.88 sys=0.00, real=0.33 secs]
318173.317: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 990336K->39851K(990336K)] 1258293K->358538K(1477760K), 0.2268530 secs] [Times: user=0.90 sys=0.00, real=0.23 secs]
318186.197: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 971947K->52805K(990336K)] 1290634K->392749K(1477760K), 0.2143420 secs] [Times: user=0.86 sys=0.00, real=0.21 secs]
318198.798: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 984901K->37920K(990336K)] 1324845K->406327K(1477760K), 0.1991210 secs] [Times: user=0.78 sys=0.01, real=0.20 secs]
318220.197: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 970016K->58223K(990336K)] 1338423K->464879K(1477760K), 0.3268740 secs] [Times: user=0.89 sys=0.00, real=0.33 secs]
318236.145: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 990319K->47118K(990336K)] 1396975K->499503K(1477760K), 0.2392560 secs] [Times: user=0.95 sys=0.00, real=0.24 secs]
318236.385: [Full GC [PSYoungGen: 47118K->0K(990336K)] [ParOldGen: 452385K->209010K(487424K)] 499503K->209010K(1477760K) [PSPermGen: 29494K->29494K(29760K)], 1.1238380 secs] [Times: us
er=3.77 sys=0.00, real=1.12 secs]
318252.638: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 932096K->48890K(990336K)] 1141106K->257901K(1477760K), 0.1462900 secs] [Times: user=0.57 sys=0.00, real=0.15 secs]
318266.585: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 980986K->36224K(990336K)] 1189997K->285813K(1477760K), 0.2157010 secs] [Times: user=0.87 sys=0.00, real=0.21 secs]
318284.570: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 968320K->58223K(990336K)] 1217909K->357684K(1477760K), 0.3613920 secs] [Times: user=1.01 sys=0.00, real=0.36 secs]
318305.316: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 990319K->36107K(990336K)] 1289780K->366282K(1477760K), 0.1913070 secs] [Times: user=0.76 sys=0.00, real=0.19 secs]
318319.138: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 968203K->38590K(990336K)] 1298378K->397789K(1477760K), 0.2022770 secs] [Times: user=0.79 sys=0.00, real=0.20 secs]
318334.057: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 970686K->58218K(990336K)] 1329885K->450417K(1477760K), 0.3152370 secs] [Times: user=0.84 sys=0.00, real=0.31 secs]
318349.963: [GC
Desired survivor size 59637760 bytes, new threshold 1 (max 15)
 [PSYoungGen: 990314K->57456K(990336K)] 1382513K->492497K(1477760K), 0.2528910 secs] [Times: user=1.00 sys=0.00, real=0.26 secs]
318350.216: [Full GC [PSYoungGen: 57456K->0K(990336K)] [ParOldGen: 435040K->229991K(487424K)] 492497K->229991K(1477760K) [PSPermGen: 29494K->29494K(29760K)], 1.2985640 secs] [Times: us
er=4.59 sys=0.01, real=1.30 secs]


我的想法是尽量调大新生代,保证新生代恰好可以放下一次发送过来的数据产生的对象。然后再处理玩这些数据后可以执行一次minor gc,这样由于处理这批数据产生的大部分对象都是死对象,所以minor gc后复制到老年代的对象很少。这样可以保证高效率的minor gc,不至于major gc频繁。。。。
zhangyou1010 2011-11-14
map实例化的时候,有指定map的初始容量大小吗?
blueswind8306 2011-11-14
调大新生代确实可以降低MinorGC的频率,但每次MinorGC的耗时也会相应增加,同时OldGen如果不是等比调大的话,也有可能导致FullGC反而更加频繁。另外,你说的
引用
是不是只有调大新生代恰好能够容下一批数据,就会达到这个目的?
是不一定的,因为系统的并发量和内存分配情况如果不是稳态的,那每次MinorGC的频率也是随时变化的,不一定“恰好能够”容纳下一批数据,可能能够容纳下半批数据或者两批数据,这就跟系统的并发量和分配的对象多少有关了。
Global site tag (gtag.js) - Google Analytics