JVM简单调优及一些工具的使用

我们都知道,Java语言有自动的垃圾回收的一个机制,主要做的是回收分配给对象的内存。
与此同时,也有一个词,叫做OOM(out of memory),说的就是内存用完了。
OOM有多种情况,包括堆内存溢出,方法区(运行时常量池)和元空间溢出,直接内存溢出,栈内存溢出
一般来说会使用默认参数,但是对于一些吞吐量比较大,或者生成了很多大对象的业务场景,假如是使用的一般配置的服务器,这个时候,仍旧使用默认的参数可能会造成比较频繁的OOM,这种时候,我们可以修改默认的参数,来实现简单的调优

问题定位

问题的定位离不开日志,所以我们可以在应用启动时,加上JVM的GC日志参数,以此来准确的定位问题。
官方文档关于相关日志参数的说明

java -jar -XX:+PrintGCDetails -Xloggc:gc.log.$(date +%y%m%d%H%M) wiki-0.0.1-SNAPSHOT.jar&

发生OOM之后,可以将此日志文件进行分析,一般可以将日志文件上传至某些专门的GC分析的网站,如GCeasy ,后续根据分析情况修改对应参数即可。
image-GCeasy

JVM相关参数

参数名称 含义 默认值 说明
-Xms 初始堆大小 物理内存的1/64(<1GB) 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
-Xmx 最大堆大小 物理内存的1/4(<1GB) 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
-Xmn 年轻代大小(1.4or later) 注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。整个堆大小=年轻代大小 + 老年代大小 + 持久代(永久代)大小.增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
-XX:NewSize 设置年轻代大小(for 1.3/1.4)
-XX:MaxNewSize 年轻代最大值(for 1.3/1.4)
-XX:PermSize 设置持久代(perm gen)初始值 物理内存的1/64
-XX:MaxPermSize 设置持久代最大值 物理内存的1/4
-Xss 每个线程的堆栈大小 JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.根据应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。(校长)和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:-Xss is translated in a VM flag named ThreadStackSize”一般设置这个值就可以了
-XX:NewRatio 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代) -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。
-XX:SurvivorRatio Eden区与Survivor区的大小比值 设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
-XX:+DisableExplicitGC 关闭System.gc() 这个参数需要严格的测试
-XX:PretenureSizeThreshold 对象超过多大是直接在旧生代分配 0 单位字节 新生代采用Parallel ScavengeGC时无效另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象.
-XX:ParallelGCThreads 并行收集器的线程数 此值最好配置与处理器数目相等 同样适用于CMS
-XX:MaxGCPauseMillis 每次年轻代垃圾回收的最长时间(最大暂停时间) 如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值.

JDK相关的命令行工具

  1. jps:虚拟机进程状况工具

    选项 作用
    -q 只输出LVMID(目标JVM的本地虚拟机标识符),省略主类的名称
    -m 输出虚拟机进程启动时传递给主类main()函数的参数
    -l 输出主类的全名,如果进程执行的是Jar包,输出Jar路径
    -v 输出虚拟机进程启动时jvm参数
  2. jstat:虚拟机统计信息监视工具

    用于监视虚拟机各种运行状态信息

    选项 作用
    -class 监视类装载,卸载数量,总空间及类装载所耗费的时间
    -gc 监视Java堆状况
    -gccapacity 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用的最大和最小空间
    -gcutil 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
    -gccause 与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因
    -gcnew 监视新生代GC的状况
    -gcnewcapacity 监视内容与-gcnew基本相同,输出主要关注使用到的最大和最小空间
    -gold 监视老年代GC的状况
    -gcoldcapacity 监视内容与-gcold基本相同,输出主要关注使用到的最大和最小空间
    -gcpermcapacity 输出永久代使用到的最大和最小空间
    -compiler 输出JIT编译器编译过的方法,耗时等信息
    -printcompilation 输出以及被JIT编译的方法
    # 每300毫秒查询一次进程86137的垃圾收集情况,一共查询10次
    jstat -gcutil 86137 300 10
    S0 S1 E O M CCS YGC YGCT FGC FGCT CGC CGCT GCT
    0.00 100.00 13.89 15.17 97.15 90.87 10 0.121 0 0.000 4 0.027 0.148
    0.00 100.00 13.89 15.17 97.15 90.87 10 0.121 0 0.000 4 0.027 0.148
    0.00 100.00 13.89 15.17 97.15 90.87 10 0.121 0 0.000 4
  3. jinfo:Java配置信息工具

    实时的查看和调整虚拟机的各项参数

    jinfo -flag CMSInitiatingOccupancyFraction 86137
    -XX:CMSInitiatingOccupancyFraction=-1
  4. jmap:Java内存映像工具

    用于生成堆转储快照

    转储快照可以帮助定位程序问题出现的原因,如CPU占用率过高、长时间停顿、死锁、阻塞的问题

    选项 作用
    -dump 生成Java堆转储快照
    -finalizerinfo 显示在F-Queue中等待Finalizer线程执行finalize方法的对象
    -heap 显示Java堆详细信息,如使用哪种回收器,参数配置,分代状况等
    -histo 显示堆中对象统计信息,包括类,实例数量和合计容量
    -permstat 以ClassLoader为统计口径显示永久代内存状态
    -F 当虚拟机进程堆-dump选项没有响应时,可使用这个选项强制生成dump快照
  5. jhat:虚拟机堆转储快照分析工具

    jhat ***.bin
  6. jstack:Java堆栈跟踪工具

    用于生成虚拟机当前时刻的线程快照

    选项 作用
    -F 当正常输出的请求不被响应时,强制输出线程堆栈
    -l 除堆栈外,显示关于锁的附加信息
    -m 如果调用到本地方法的话,可以显示C/C++的堆栈