通过这个看启动参数,java jvm 参数 -Xms -Xmx -Xmn -Xss 调优总结
-Xms初始Heap大小,-Xmx Heap最大值,一般设置一样大
PermSize表示持久带
-Xmn设置年轻带大小
-Xss128k:设置每个线程的堆栈大小.JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值.设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代).设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
XX:CMSInitiatingOccupancyFraction=80,当old space的空间占用达到80%后会强制JVM执行CMS。
XX:+CMSClassUnloadingEnabled允许CMS回收永久代的不可到达对象, 默认情况下,JVM的CMS是不会去回收永久代的对象,
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
admin 6758 70.2 64.0 6492928 4915416 ? SNl Apr20 5605:40 /opt/java/bin/java -Dprogram.name=run.sh -server -Xms4g -Xmx4g -XX:PermSize=96m -XX:MaxPermSize=256m -Xmn2560m -XX:SurvivorRatio=10 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSMaxAbortablePrecleanTime=5000 -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=80 -XX:+DisableExplicitGC -verbose:gc -Xloggc:/home/XXX/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseCompressedOops -Djava.awt.headless=true -Dsun.net.client.defaultConnectTimeout=10000 -Dsun.net.client.defaultReadTimeout=30000 -Djava.net.preferIPv4Stack=true -Djava.endorsed.dirs=/opt/taobao/jboss/lib/endorsed -classpath /opt/taobao/jboss/bin/run.jar:/opt/taobao/java/lib/tools.jar org.jboss.Main -b 0.0.0.0 -Djboss.server.home.dir=/home/admin/xu/.default -Djboss.server.home.url=file:/home/admin/xu/.default
How to Monitor Java Garbage Collection
-verbose:gc可以显示堆和gc的一些信息,比如:
[GC 325407K->83000K(776768K), 0.2300771 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]
两次minor gc之后发生了一次full gc,325407K->83000K表明gc之前存活的对象大小,以及gc后的大小,776768表示不再使用被回收的对象,0.2300771sec表示执行回收的时间,
使用-XX:+PrintGCDetails参数,可以增加更多的信息,比如
[GC [DefNew: 64575K->959K(64576K), 0.0457646 secs] 196016K->133633K(261184K), 0.0459067 secs]
表明minor gc回收了98%的空间,从64575K到959K,花费了0.0457sec,整个堆减少了51%,从196016K->133633K(261184K)到,猜测应该是包括了部分从young拷贝对象到tenued的时间,稍有增加,为0.0459sec
-XX:+PrintGCTimeStamps参数会在gc开始前添加时间戳,可以方便的判断gc发送的频率
111.042: [GC 111.042: [DefNew: 8128K->8128K(8128K), 0.0000505 secs]111.042: [Tenured: 18154K->2311K(24576K), 0.1290354 secs] 26282K->2311K(32704K), 0.1293306 secs]
发生minor gc的同时还发生了major gc
2012-12-19T13:58:18.122+0800: 13197.398: [GC 13197.398: [ParNew: 752045K->16071K(829440K), 0.0574310 secs] 2119069K->1384051K(4102144K), 0.0576820 secs] [Times: user=0.20 sys=0.00, real=0.05 secs]
[1] real : 表示foo程序整个的运行耗时,可以理解运行开始时刻你看了一下手表,运行结束时,你又看了一下手表,两次时间的差值就是本次real 代表的值
User 是在用户态下的CPU时间总和
Sys 是内核态下的CPU时间总和
User+Sys表示总共的CPU利用时间,除以real可以得出CPU利用率
误区一: real_time = user_time + sys_time
我们错误的理解为,real time 就等于 user time + sys time,这是不对的,real time是时钟走过的时间,user time 是程序在用户态的cpu时间,sys time 为程序在核心态的cpu时间。
利用这三者,我们可以计算程序运行期间的cpu利用率如下:
%cpu_usage = (user_time + sys_time)/real_time * 100%
如:
# time sleep 2
real 0m2.003s
user 0m0.000s
sys 0m0.000s
cpu利用率为0,因为本身就是这样的,sleep 了2秒,时钟走过了2秒,但是cpu时间都为0,所以利用率为0
误区二:real_time > user_time + sys_time
一般来说,上面是成立的,上面的情况在单cpu的情况下,往往都是对的。
但是在多核cpu情况下,而且代码写的确实很漂亮,能把多核cpu都利用起来,那么这时候上面的关系就不成立了,例如可能出现下面的情况,请不要惊奇。
real 1m47.363s
user 2m41.318s
sys 0m4.013s
调优
到目前为止调优两次
一次是因为相同内存配置的两个应用,有一个应用的minor gc时间远远大于另一个应用,不解,因此就想着调笑young之类的,但是调小了gc次数也变多了,整体停顿时间可能没相差太多;还试过parallel scavenge的自动调整策略,限制minor gc时间在40ms以下,他就是调小了young,也没什么特别
另一次是发现每次minor gc之后总有对象晋升到old区,开始以为是survivor太小,也看过晋升阀值在4次左右,因此就调大了survivor,但是发现cms gc反而频繁了,估计是因为old变小的缘故;调大了survivor之后,并不是每次mior gc都有对象晋升,但是观察发现到后面第14,15次拷贝的时间,对象已经基本没有减少(最多减少1K左右),剩余的大部分对象都只是在重复拷贝罢了
这也可能和我们的应用有关,我们的缓存会保留比较长的时间(起码10分钟),所以调大survivor也只是白白浪费时间
总的来说,两次调优都以失败告终,fuck!!!
联系客服