JVM参数调优

一、背景

以前有一篇文章讲到JVM堆内存分代划分和对象在堆上的分配机制 ,详细可读 JVM堆内存解析,今天我们来聊一下怎么通过配置JVM参数,对系统性能进行优化,本文以JDK1.8做为实验环境

二、基本参数介绍

1、常用堆分配参数

  • -Xmx:最大堆内存,如果程序运行超过这个值会报OOM,如果不设置一般默认为操作系统物理内存的1/4。

  • -Xms:初始堆内存,当初始堆不够,虚拟机会对堆空间扩展直至上限为最大堆空间,一般工作中将-Xms与-Xms设置为相等,这样可以减少垃圾回收次数。

  • -Xmn:新生代堆内存,一般默认为堆内存的1/4.

  • -XX:SurvivorRatio  :设置Eden区与Survivor区的比值。

2、跟踪监控参数

  • -XX:+PrintGC

    打印GC简要信息

上面的日志发生了两次普通GC和一次FullGC,后面的数值表示 GC前堆内存使用大小,GC后内存使用大小,括号中是整个堆的大小。这里也可以看出FullGC耗时是普通GC的好几倍。

  • -XX:+PrintGCDetails

    打印GC详细信息和堆的详细信息

JVM参数调优_第1张图片

第一次普通GC:[GC (Allocation Failure) [PSYoungGen: 404K->320K(1536K)] 3476K->3400K(5632K), 0.0006883 secs]

PSYoungGen: 404K->320K(1536K):新生代GC前后空间使用大小,3476K->3400K(5632K)整个堆内存GC前后空间使用大小。

第一次FullGC:[Full GC (Allocation Failure) [PSYoungGen: 288K->0K(1536K)] [ParOldGen: 3080K->1282K(4096K)]

3368K->1282K(5632K), [Metaspace: 2490K->2490K(1056768K)]

PSYoungGen:FullGC前后新生代空间使用大小,ParOldGen :FullGC前后老年代空间使用大小。

  • -Xloggc:log/gc.log:

    将GC日志记录到外部文件

  • -XX:+TraceClassLoading 

    监控类的加载情况

  • -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath

    发生OOM异常时把堆栈信息打印到外部文件

三、一个JVM参数优化例子

下面一个程序连续向系统请求10M空间(每次请求1M),使用不同参数GC的情况完全不同。

JVM参数调优_第2张图片

1、java -Xmx20m -Xms20m -Xmn1m -XX:SurvivorRatio=2

-XX:+PrintGCDetails TestVM

由于eden区的空间大小为512K,无法容纳每次生成的1MB数组,这种就是大对象,直接分配在老年代,老年代最终占用内存为used 10240K。注:from区和to不受-XX:SurvivorRatio设置的影响,这是因为from和to已经是足够小了。

2、java -Xmx20m -Xms20m  -Xmn7m -XX:SurvivorRatio=8 

-XX:+PrintGCDetails TestVM   将新生代内存扩大到7M

JVM参数调优_第3张图片

由于eden区的空间大小为6M有足够的空间,但又并不足以有10M空间,所以发生了一次GC,由于每申请一次空间,同时也废弃上次申请的空间(上次申请的失去引用),做GC时被回收。老年代空间几乎没有被占用。

3、java -Xmx20m -Xms20m  -Xmn15m -XX:SurvivorRatio=8

-XX:+PrintGCDetails TestVM  新生代分配15M空间

由于eden区的空间大小为12288K,完全满足10M数组的分配,因此没有触发GC,from/to区、老年代空间都为0.

总结:不同的堆空间分配对系统会产生一定的影响,基本策略是尽可能将对象预留在新生代,减少老年代GC的次数。

四、Java Performance推荐公式

1、Java整个堆大小设置,Xmx 和 Xms设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍。

2、老年代的内存大小设置为老年代存活对象的2-3倍。

3、年轻代Xmn的设置为老年代存活对象的1-1.5倍。

注:老年代FullGC后的内存占用,可以根据生产环境日志观察一段时间得出一个平均值。

五、Runtime几个方法

  • maxMemory():最大内存,对应于参数-Xmx设置的值,如果没有设置,一般为物理内存的1/4。这表示可以从操作系统拿多少内存给JAVA进程使用,如果程序运行时占用的内存超过了这个数,就OOM了。

  • totalMemory():当前JVM内存量,程序运行时已经从系统中挖过来的内存。

  • freeMemory():从操作系统挖过来但又没有使用的内存。

你可能感兴趣的:(Java技术,jvm)