JAVA教程:浅谈JVM的优化

浅谈JVM的优化

前言

前面我们了解过JVM中堆的GC分代回收机制,在运行Java程序时,我们可以使用JVM的参数对程序的执行过程进行优化,以达到更优的内存配置和GC配置,从而提高程序的性能和稳定性。


JVM的参数

JVM的参数分为三种:

标准参数

非标准参数

非稳定参数

标准参数以-开头,如:java -version、java -jar等,通过java -help可以查询所有的标准参数,本章不具体讨论。


非标准参数以-X开头,是标准参数的扩展,输入:java -X可以查询所有非标准参数。我们可以通过设置非标准参数来配置堆的内存分配,常用的非标准参数有:

-Xmn新生代内存的最大值,包括Eden区和两个Survivor区的总和,写法如:-Xmn1024,-Xmn1024k,-Xmn1024m,-Xmn1g 。

-Xms堆内存的最小值,默认值是总内存/64(且小于1G),默认情况下,当堆中可用内存小于40%(这个值可以用-XX: MinHeapFreeRatio 调整,如-X:MinHeapFreeRatio=30)时,堆内存会开始增加,一直增加到-Xmx的大小。

-Xmx堆内存的最大值,默认值是总内存/64(且小于1G),如果Xms和Xmx都不设置,则两者大小会相同,默认情况下,当堆中可用内存大于70%时,堆内存会开始减少,一直减小到-Xms的大小;

整个堆的大小=年轻代大小+年老代大小,堆的大小不包含持久代大小,如果增大了年轻代,年老代相应就会减小,官方默认的配置为年老代大小/年轻代大小=2/1左右;

建议在开发测试环境可以用Xms和Xmx分别设置最小值最大值,但是在线上生产环境,Xms和Xmx设置的值必须一样,原因与年轻代一样——防止抖动;

-Xss每个线程的栈内存,默认1M,一般来说是不需要改的。

-Xrs减少JVM对操作系统信号的使用。

-Xprof跟踪正运行的程序,并将跟踪数据在标准输出输出;适合于开发环境调试。

-Xnoclassgc关闭针对class的gc功能;因为其阻止内存回收,所以可能会导致OutOfMemoryError错误,慎用;

-Xincgc开启增量gc(默认为关闭);这有助于减少长时间GC时应用程序出现的停顿;但由于可能和应用程序并发执行,所以会降低CPU对应用的处理能力。

-Xloggc:file与-verbose:gc功能类似,只是将每次GC事件的相关情况记录到一个文件中,文件的位置最好在本地,以避免网络的潜在问题。


非稳定参数,以-XX开头,官方介绍这些参数是不稳定的,但往往在进行JVM优化时,这些参数能起到重要作用。

非稳定参数分为三类:

性能参数:用于JVM的性能调优和内存分配控制,如内存大小的设置;

行为参数:用于改变JVM的基础行为,如GC的方式和算法的选择;

调试参数:用于监控、打印、输出jvm的信息;

使用方法有三种:

-XX:+<选项> 启用选项

-XX:-<选项> 不启用选项

-XX:<选项>=<数值> 给选项设置一个数字类型值,如 32k, 1024m, 2g

-XX:<选项>=<字符串> 给选项设置一个字符串值,如

-XX:HeapDumpPath=./dump.core

常用性能参数:

参数及其默认值描述
-XX:NewSize=2.125m新生代对象生成时占用内存的默认值
-XX:MaxNewSize=size新生成对象能占用内存的最大值
-XX:MaxPermSize=64m方法区所能占用的最大内存(非堆内存)
-XX:PermSize=64m方法区分配的初始内存
-XX:MaxTenuringThreshold=15对象在新生代存活区切换的次数(坚持过MinorGC的次数,每坚持过一次,该值就增加1),大于该值会进入老年代
-XX:MaxHeapFreeRatio=70GC后java堆中空闲量占的最大比例,大于该值,则堆内存会减少
-XX:MinHeapFreeRatio=40GC后java堆中空闲量占的最小比例,小于该值,则堆内存会增加
-XX:NewRatio=2新生代内存容量与老生代内存容量的比例
-XX:ReservedCodeCacheSize= 32m保留代码占用的内存容量
-XX:ThreadStackSize=512设置线程栈大小,若为0则使用系统默认值
-XX:LargePageSizeInBytes=4m设置用于Java堆的大页面尺寸
-XX:PretenureSizeThreshold= size大于该值的对象直接晋升入老年代(这种对象少用为好)
-XX:SurvivorRatio=8Eden区域Survivor区的容量比值,如默认值为8,代表Eden:Survivor1:Survivor2=8:1:1

常用行为参数:

参数及其默认值描述
-XX:-UseSerialGC启用串行GC,即采用Serial+Serial Old模式
-XX:-UseParallelGC启用并行GC,即采用Parallel Scavenge+Serial Old收集器组合(-Server模式下的默认组合)
-XX:GCTimeRatio=99设置用户执行时间占总时间的比例(默认值99,即1%的时间用于GC)
-XX:MaxGCPauseMillis=time设置GC的最大停顿时间(这个参数只对Parallel Scavenge有效)
-XX:+UseParNewGC使用ParNew+Serial Old收集器组合
-XX:ParallelGCThreads设置执行内存回收的线程数,在+UseParNewGC的情况下使用
-XX:+UseParallelOldGC使用Parallel Scavenge +Parallel Old组合收集器
-XX:+UseConcMarkSweepGC使用ParNew+CMS+Serial Old组合并发收集,优先使用ParNew+CMS,当用户线程内存不足时,采用备用方案Serial Old收集。
-XX:-DisableExplicitGC禁止调用System.gc();但jvm的gc仍然有效
-XX:+ScavengeBeforeFullGC新生代GC优先于Full GC执行

常用调试参数:

参数及其默认值描述
-XX:-CITime打印消耗在JIT编译的时间
-XX:ErrorFile=./hs_err_pid<pid>.log保存错误日志或者数据到文件中
-XX:-ExtendedDTraceProbes开启solaris特有的dtrace探针
-XX:HeapDumpPath=./java_pid<pid>.hprof指定导出堆信息时的路径或文件名
-XX:-HeapDumpOnOutOfMemoryError当首次遭遇OOM时导出此时堆中相关信息
-XX:OnError=”<cmd args>;<cmd args>”出现致命ERROR之后运行自定义命令
-XX:OnOutOfMemoryError=”<cmd args>;<cmd args>”当首次遭遇OOM时执行自定义命令
-XX:-PrintClassHistogram遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同
-XX:-PrintConcurrentLocks遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同
-XX:-PrintCommandLineFlags打印在命令行中出现过的标记
-XX:-PrintCompilation当一个方法被编译时打印相关信息
-XX:-PrintGC每次GC时打印相关信息
-XX:-PrintGC Details每次GC时打印详细信息
-XX:-PrintGCTimeStamps打印每次GC的时间戳
-XX:-TraceClassLoading跟踪类的加载信息
-XX:-TraceClassLoadingPreorder跟踪被引用到的所有类的加载信息
-XX:-TraceClassResolution跟踪常量池
-XX:-TraceClassUnloading跟踪类的卸载信息
-XX:-TraceLoaderConstraints跟踪类加载器约束的相关信息

常见的配置

典型的JVM配置:

java -Xmx2048m -Xms2048m -Xmn2g -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0

参数说明:

-Xmx2048m :堆的最大内存为2048M。

-Xms2048m :堆的最小内存为2048m。最大内存和最小内存配置相同,以避免每次垃圾回收完成后JVM重新分配内存也就是抖动。

-Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,官方推荐配置为整个堆的3/8。

-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。

-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比例(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5

-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比例。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6

-XX:MaxPermSize=16m:设置持久代大小为16m。

-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。

GC的选择

JVM中有三种垃圾收集器:

串行收集器

性能不高,只适合数据不多的应用

并行收集器

能达到较高的吞吐量,适用于科学技术和后台处理等

并发收集器

能保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等

典型的JVM配置

1)

java -Xmx2048m -Xms2048m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20

说明:

-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。

-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。


2)

java -Xmx2048m -Xms2048m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC

-XX:+UseConcMarkSweepGC:设置年老代为并发收集。

-XX:+UseParNewGC: 设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。

调优总结

响应时间优先的应用

将年轻代尽量设置大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。

年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。

吞吐量优先的应用

将年轻代尽设置大量,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。

一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值