先来看下一X宝经典配置:
/opt/taobao/java/bin/java -Dprogram.name=run.sh –server
-Xms4g //指定 jvm 的最小 heap 大小
-Xmx4g //指定 jvm 的最大 heap 大小
-Xmn2g
-Xss1m
-XX:PermSize=96m
-XX:MaxPermSize=256m
-XX:SurvivorRatio=10
-XX:+HeapDumpOnOutOfMemoryError //
-XX:HeapDumpPath=/home/admin/logs/java.hprof -verbose:gc -Xloggc:/home/admin/logs/gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+UseConcMarkSweepGC
-XX:+UseCMSCompactAtFullCollection
-XX:CMSInitiatingOccupancyFraction=80
-XX:+UseCompressedOops
-XX:+DisableExplicitGC
-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/purdecision/.default -Djboss.server.home.url=file:/home/admin/purdecision/.default
这二年来这一堆东西我从来没有怀疑过,“绝对正确完美”,据说是X宝的标配。以至于从来没有去分析了解过(一知半解),可能真的是惰性使然,也可能“忙”吧。无意中看到有人在博客里写到 “温故知新”,就像有人说读think in java一样每一回都有新的发现。下面就分析一下为什么要设置这些参数,有何意义。
上面参数说明:
-Xmx4g :
指定 jvm 的最大 heap 大小,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定
-Xms4g :
指定 jvm 的最小 heap 大小。些值设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存
-Xmn2g :
设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般
固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推
荐配置为整个堆的3/8。(按此说应设置为1.5G)
-Xss1m
每个线程堆栈大小为1M. 根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。(本机由于forest的原因-Xss2m,原因1:物理内存过小 2:window线程不能太多 猜的)
-XX:PermSize=96m
用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或
者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新
增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置
-XX:PermSize=64MB 最小尺寸,初始分配
-XX:MaxPermSize=256MB 最大允许分配尺寸,按需分配
过小会导致:java.lang.OutOfMemoryError: PermGen space
MaxPermSize缺省值和-server -client选项相关。
-server选项下默认MaxPermSize为64m
-client选项下默认MaxPermSize为32m
(为什么不是64M 可能是webx设置的持久代空间比较多)
-XX:SurvivorRatio=10
(SurvivorRatio=4设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor
区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6)
这里设置为10也就是说一个Survivor区占整个年轻代的1/12,这个参数是否能小一点,毕竟我们的应用中没有创建很大的对像。
这个值设了有什么用?
上面配置中-Xmn2g 年轻代大小,SurvivorRatio为10时 :Eden超过1.66G时触发minor gc(young generation)
我的应用gc 日志一直在young gc 就是如此,看来我的应用 eden区还是设的很大的。
-XX:+HeapDumpOnOutOfMemoryError
参数表示当JVM发生OOM时,自动生成DUMP文件。
-XX:HeapDumpPath=${目录}参数表示生成DUMP文件的路径,也可以指定文件名称,例如:-XX:HeapDumpPath=${目录}/java_heapdump.hprof。如果不指定文件名,默认为:java_<pid>_<date>_<time>_heapDump.hprof。
-XX:+PrintGCDetails:
输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured:
112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]
-XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可与上面两个混合使用
输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-XX:+UseConcMarkSweepGC
设置并发收集器
可以保证大部分工作都并发进行(应用不停止),垃圾回收只暂停很少的时间,此收集器适合对响应时间要求
比较高的中、大规模应用。使用-XX:+UseConcMarkSweepGC打开。
并发收集器主要减少年老代的暂停时间,他在应用不停止的情况下使用独立的垃圾回收线程,跟踪可达对
象。在每个年老代垃圾回收周期中,在收集初期并发收集器 会对整个应用进行简短的暂停,在收集中还会再暂
停一次。第二次暂停会比第一次稍长,在此过程中多个线程同时进行垃圾回收工作。
CMS采用的基础算法是:标记—清除 所有CMS不会整理、压缩堆空间。这样就会有一个问题:经过CMS收集的堆会产生空间碎片
-XX:CMSInitiatingOccupancyFraction=80
启动并发收集器:因为并发收集在应用运行时进行收集,所以必须保证收集完成之前有足够的内存空间供程
序使用,否则会出现“Concurrent Mode Failure”。通过设置-XX:CMSInitiatingOccupancyFraction=<N>
指定还有多少剩余堆时开始执行并发收集
-XX:+UseCMSCompactAtFullCollection:
打开对年老代的压缩。可能会影响性能,但是可以消除碎片
XX:+UseCompressedOops
通常64位JVM消耗的内存会比32位的大1.5倍,这是因为对象指针在64位架构下,长度会翻倍(更宽的寻址)。
对于那些将要从32位平台移植到64位的应用来说,平白无辜多了1/2的内存占用,这是开发者不愿意看到的。
幸运的是,从JDK 1.6 update14开始,64 bit JVM正式支持了 -XX:+UseCompressedOops 这个可以压缩指针,起到节约内存占用的新参数
-XX:-DisableExplicitGC
将会忽略手动调用GC的代码,如:System.gc(),将-DisableExplicitGC, 改成+DisableExplicitGC即为启用,默认为启用,什么也不写,默认是加号,但是系统内部默认的并不是什么都启用
至此为什么Xmx与xms 一样,为什么用CMS(并发收集器),为什么用了cms 要使用-XX:+UseCMSCompactAtFullCollection,为什么用XX:+UseCompressedOops等等,相信大家和我一样有所了解。不过对于有些还是不清楚理解有误,可能还要来来回回捣腾,不足之处请大家补充。