一、概述

前面的的博文中我们了解了虚拟机的内存管理、垃圾收集、类加载机制等,那么最终还是需要将这些知识发挥到实际的应用中,这才是我们学习这个知识的最终目的,既然需要解决实际中的问题,那么就需要知道虚拟机相关的参数,配置虚拟机或者遇到问题的时候才能更加准确的知道怎么去配置哪个参数,为什么需要配置这个参数,下面我们就来看看一些常用的参数。

二、参数说明

1.调整堆大小

通过前面的学习我们都已经知道堆是这个内存模型中分配,也是容易造成内存溢出的地方,所以如何更好的设置堆和堆中相关内存区域的大小对我们来说非常的重要,首先看一下JVM堆的分布情况


java 虚拟机参数 java虚拟机参数含义_调优

堆内存分布图

 上图如果不明白可以查阅:《深入理解java虚拟机》---内存管理(2)

  • -Xms<n>[g|m|k]:调整堆的最小大小,比如:-Xms1G,表示堆最小为1G,在系统启动阶段JVM直接向系统申请1G内存,此参数相当于参数-XX:InitialHeapSize=n[g|m|k],物理内存的1/64;
  • -Xmx<n>[g|m|k]:调整堆的最大大小,比如:-Xms1G表示堆最大为1G,此参数相当于参数-XX:MaxHeapSize=n[g|m|k],物理内存的1/4;
  • -Xmn<n>[g|m|k]:年轻代大小(1.4or lator),此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小,增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
  • -XX:MinHeapFreeRatio=n,指定堆最小空余比例,当堆中空余内存比例小于该参数指定值时,JVM将增大内存大小直到最大堆大小,默认40;
  • -XX:MaxHeapFreeRatio=n,指定堆最大空余比例,当堆中空余比例大于该参数制定值,JVM将减少内存大小,直到最小堆大小,默认为70;
    JVM将在发生FGC之后,根据这两个参数调整整个对的大小,FGC一般消耗的时间较多,为了降低延迟,一般将最小堆大小和最大堆大小设置成一样的。
  • -XX:NewRatio=n,老年代与新生代内存占比,-XX:NewRatio=4表示年轻代是老年代内存的1/4,也就是说年轻代占用总堆内存的1/5;
  • -XX:SurvivorRatio=n,Eden区与1个survivor区域内存占比,-XX:SurvivorRatio=8,表示EdenEden区域的内存是一个survivor区域内存的8倍,一共两个survivor区域,因此survivor占用新生代的1/10;
  • -XX:PermSize=<n>[g|m|k],物理内存的1/4,-XX:MaxPermSize=<n>[g|m|k],物理内存的1/64,这两个参数用于制定永久代内存大小,这个两个参数在jdk8中已经失效;
  • -XX:MetaspaceSize=<n>[g|m|k], -XX:MaxMetaspaceSize=<n>[g|m|k],在jdk中使用这两个参数指定元数据空间大小;
  • -XX:TargetSurvivorRatio=n,设定survivor区的目标使用率,默认是50%;
  • -XX:MaxDirectMemorySize=<n>[g|m|k],设置直接内存的大小,在使用一些nio框架时最好设置一下此参数,此参数如果过小也有可能导致频繁触发FGC;
  • -Xss<n>[g|m|k],指定Java线程栈的大小,默认值受环境影响,Xss越大,进程能运行的最大线程数就少,如果设置的过小,容易导致StackOverflowError错误;

 上面的参数配置使用比较多的是-Xms、-Xmx,一般设置的时候值是一样的,其目的是为了能够在java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小而浪费资源。其次是-XX:PermSize、-XX:MaxPermSize,现在随着应用的复杂化,编译后的.class文件是越来越来越多,因为默认的永久代也就是方法区的最大内存限制很容易导致内存溢情况,这样就需要重新设置这两个参数。以上情况的具体事例可以查阅:IDEA解决运行项目虚拟内存溢出问题

2.指定垃圾收集器

  • -XX:+UseSerialGC 指定使用串行垃圾收集器,新生代及老年代都是串行收集,在大堆或者多核cpu的环境中不大适合使用该种垃圾收集器
  • -XX:+UseParallelGC,并行垃圾收集器,新生代使用并行收集,老年代使用串行收集
  • -XX:+UseParallelOldGC,并行垃圾收器,新生代使用并行手机,老年代使用并行收集,在一些低版本的JVM该参数不支持或者不生效,这两种垃圾收集适合不在乎延时需要高吞吐的环境下使用,比如说一些批处理程序,
  • -XX:+UseConcMarkSweepGC,并发垃圾收集,新生代使用并行收集,老年代采用并发收集,适合低延迟应用使用该种垃圾器。使用并发垃圾收集,相当于自动添加了参数-XX:+UseParNewGC
  • -XX:+UseG1GC,使用G1垃圾收集,该种垃圾收集器比较复杂,目前在此种垃圾收集的调优经验较少,在需要大堆的应用可以考虑使用,相比并发垃圾收集器,其产生的碎片更少,且可以通过参数控制垃圾收集过程中的停顿时间。

 3.CMS垃圾收集器参数

调优CMS垃圾收集器比调优吞吐量垃圾收集器复杂许多,下面列出一些用于设置CMS收集器的参数:

  • -XX:CMSInitiatingOccupancyFraction=n,设置CMS垃圾收集器启动回收老年代的时机,当老年代对象占比超过n时,就启动一次CMS回收周期,注意:这个参数只是设定首次CMS垃圾回收;
  • -XX:+UseCMSInitiatingOccupancyOnly,使用这个参数可以使CMS一直按照CMSInitiatingOccupancyFraction设定的值启动;
  • -XX:CMSInitiatingPermOccupancyFraction=n,设置永久代内存占比超过n启动cms回收,此参数需要配合参数-XX:+CMSClassUnloadingEnabled一起使用(Java8默认开启);
  • -XX:+CMSParallelInitialEnabled, 用于开启CMS initial-mark阶段采用多线程的方式进行标记,用于提高标记速度,在Java8开始已经默认开启;
  • -XX:+CMSParallelRemarkEnabled,用户开启CMS remark阶段采用多线程的方式进行重新标记,默认开启;
  • -XX:CMSFullGCsBeforeCompaction,我们知道cms垃圾收集器会产生内存碎片,该参数用于设置多少次CMS gc之后进行一次内存压缩;该参数默认值为0;
  • -XX:+ExplicitGCInvokesConcurrent 、-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses这两个参数用户指定hotspot虚拟在执行System.gc()时使用CMS周期;
  • -XX:+CMSScavengeBeforeRemark,强制hotspot虚拟机在cms remark阶段之前做一次minor gc,用于提高remark阶段的速度;
  • -XX:ConcGCThreads=n,设置并发垃圾收集的线程数,默认该值是基于ParallelGCThreads计算出来的;
  • -XX:+CMSPrecleaningEnabled,指定CMS是否需要进行Pre cleaning这个阶段,这个阶段的主要工作是:1、在并发标记阶段阶段由于业务线程同步在跑,新生代中对象有可能引用到老年代的对象,产生新的引用关系,这个时候需要重新标记出老年代中被引用的对象;2、老年代中对象引用关系发生变化,这个需要把引用关系发生变化的卡表(card table)标记为dirty,提高remark标记的效率;
  • -XX:CMSMaxAbortablePrecleanTime=n,设置cms abortable pre阶段最长持续时间,单位为s,默认值5s。abortable prelean阶段默认在Eden区大于2M启动(通过参数:-XX:CMSScheduleRemarkEdenSizeThreshold =n设置),直到Eden区域占用率超过50%(通过参数:-XX:CMSScheduleRemarkEdenPenetration=n)时结束,同时还可以指定参数-XX:CMSMaxAbortablePrecleanLoops=n设置该阶段的循环次数(默认0,表示不限制次数),为了防止abortable pre clean阶段陷入无限等待,故设置一个最长的持续时间,达到最长持续时间之后,该阶段终止,进入remark阶段;

4.收集gc日志

  • -verbose:gc,输出gc日志信息,默认输出到标准输出,参数与-XX:+PrintGCDetails作用一致;
  • -XX:+PrintGCDetails,打印gc日志,打印的出日志包含日志收集原因,歌区域变化情况,以及用时;
  • -XX:+PrintGCDateStamps,日志中输出时间戳;
  • -XX:+PrintGCTimeStamps,日志中输出时间戳,与PrintGCDateStamps参数不同的地方在于,此参数输出的时间是相对与应用启动时间的差值;
  • -Xloggc:filename,把gc日志信息输入到指定文件中,
  • -XX:+PrintGCApplicationStoppedTime,打印垃圾收集期间应用被暂停的时间;
  • -XX:+PrintGCApplicationConcurrentTime,垃圾收集之前打印出应用未中断的执行时间;
  • -XX:+UseGCLogFileRotation, -XX:GCLogFileSize=n,这两个参数用于设置gc文件滚动和设置滚动日志文件的个数,为了防止单个gc日志文件太大,生产上建议加上这两个参数;

5.其他参数

  • -XX:+DisableExplicitGC,禁止hotspot执行System.gc(),默认禁用;
  • -XX:+ScavengeBeforeFullGC,在执行full gc之前执行一次minor gc,默认开启;
  • -XX:MaxTenuringThreshold=n,设定新生代的对象在经历多少次minor gc之后将转移到老年代,默认是15;
  • -XX:+HeapDumpOnOutOfMemoryError,在hotspot发生OOM时打印出堆,默认打印到应用工作目录,文件名称为java_pid%p.hprof;
  • -XX:HeapDumpPath=xx,指定hotspot虚拟机OOM时堆转储文件的path;
  • -XX:ErrorFile=xx,设置JVM crash时生成crash文件的路径,默认为./hs_err_pid%p.log;
  • -XX:+ParallelRefProcEnabled,采用多线程的方式发现需要处理的finalize方法的对象,非多线程执行对象的finalize方法;
  • -XX:ParallelGCThreads=n,设置并行收集的线程数,默认值采用Runtime.getRuntime().availableProcessors()来确定。不过是建立在返回值小于等于8的情况下,反之,会使用Runtime.availableProcessors()*5/8作为线程数。
  • -XX:+UseAdaptiveSizePolicy,开启自适应调整JAVA内存策略,在使用吞吐量垃圾收集器时,该参数用于让jvm自行调整Eden区和Survivor区空间的大小,新生代与老年代空间的大小;
  • -XX:+PrintAdaptiveSizePolicy,可以打印出survivor的一些详细信息,关于survivor区间是否溢出,是否有对象转移到老年代;
  • -XX:+PrintTenuringDistribution,显示出survivor区间有效对象的年龄分布情况,可以通过该参数的输出确定出survivor大小以及MaxTenuringThreshold的值;
  • -XX:MaxGCPauseMillis=n,设置最大gc停顿时间,这个时间不是设置的越小越好,此参数只在ps收集器上有效,不建议修改此参数的值;
  • -XX:GCTimeRatio,设置垃圾收集时间占总时间的比率,默认为99,也就是说垃圾收集时间占用总时间的1%,此参数只在ps收集器上有效;
  • -XX:+HeapDumpAfterFullGC,在执行一次FGC之后打印出Heap到文件;
  • -XX:+HeapDumpBeforeFullGC,在执行一次FGC之前打印出Heap到文件,这两个参数主要用于调试;
  • -XX:+PrintHeapAtGC,打印gc前后堆详细信息,不管是minor gc还是full gc都会打印;
  • -XX:+GCLockerInvokesConcurrent,在执行gc之前都需要先先查看 gc locker是否被java线程持有,如果存在gc locker被持有的情况则忽略此次gc,在所有java线程完全释放gc locker之后补偿一次gc。此参数指定,如果是fgc的话,则补偿一次CMS back groud fgc。
  • -XX:ReservedCodeCacheSize=<n>[g|m|k]、-XX:InitialCodeCacheSize=<n>[g|m|k],指定代码缓存的大小,用于保存已编译方法生成的本地代码,如果代码缓存被占满JVM会发出警告信息,并切换到interpreted-only模式,JIT编译器被停用,字节码将不会再编译成机器码。这样的话对JVM的性能影响很大;
  • -XX:+UseCodeCacheFlushing,如果代码缓存不断增长导致代码缓存空间不够,使用该参数让jvm放弃一些被编译的代码,避免代码缓存被占满时JVM切换到interpreted-only的情况;
  • -XX:+DoEscapeAnalysis,开启逃逸分析,逃逸分析是一种分析对象范围的技术,在一些情况一个线程分配的对象可能会被其他对象使用,这种现象叫做“逃逸”,如果一个对象没有“逃逸”,则可以运用一些额外的优化技术,这种优化技术“逃逸分析”。通过“逃逸分析” JIT可以使用如下技术优化:
  1. 栈上分配
  2. 消灭同步
  3. 消灭垃圾回收读写障碍
  4. 对象爆炸
  • -XX:+UseBiasedLocking,开启偏向锁,偏向锁是是锁偏爱上次使用它的线程,在非竞争锁的场景下,可以实现无锁的开销。
  • -XX:+UseLargePages,开启使用大页面,使用大页面可以提高TLB(translation lookaside buffer(转换后备缓存区))的缓存命中率;
  • -XX:PretenureSizeThreshold=n,指定对象占用的字节数超过n之后直接在老年代中分配,默认值0,表示最大值;
  • -XX:+OmitStackTraceInFastThrow,一些频繁抛出的异常,JVM为了性能优化而抛出没有堆栈的异常,默认开启,
  • -XX:+PrintFlagsInitial、-XX:+PrintFlagsFinal,打印出设置的JVM参数和最终生效的JVM参数和他们的值,-XX:+PrintCommandLineFlags打印出被修改的JVM参数,一般在启动应用添加此参数打印出引用启动时添加的JVM参数,在应用运行过程中一些JVM参数可能会被修改掉(通过jinfo工具);
  • -XX:+PrintSafepointStatistics,打印安全点统计信息,-XX:PrintSafepointStatisticsCount=n设置打印安全点统计信息的次数;
    -XX:+PrintReferenceGC,打印gc时处理的reference情况;
    -XX:+UseCompressedOops,开启压缩指针,压缩指针主要是为了解决32位操作系统内存寻址范围只有4G的限制,开启压缩指针最大寻址范围增加到32G;如果内存超过32G(Xmx>32G),开启该参数无效;
    -XX:+ParallelRefProcEnabled,使用此参数激活多线程方式的引用处理,截止到目前的jdk8该参数默认关闭,如果在gc中发现处理ref处理的时间过长,可以通过参数-XX:+PrintReferenceGC打印出每次垃圾收集中记录每个引用对象类型的统计数据,另外如果发现有大量软引用正在被处理,可以使用参数-XX:SoftRefLRUPolicyPerMB调整软件用的处理策略,该参数的默认值为1000(ms),该参数的含义是,使用该参数设置的值乘以java堆可用空间(以兆为单位)的出来的值,若软引用在这段时间内没有被访问,那么这些软引用将会被回收,调优引用处理的目标主要有两点:第一是降低引用在gc过程中处理时间,第二是降低heap的占用空间,减少垃圾收集频率和最终需要复制的时间;

三、总结

上面只是说明了参数的一些说明,具体的使用得根据实际的情况来设置,最后来一张JVM运行状态图(来自JVM Internals)

java 虚拟机参数 java虚拟机参数含义_JVM_02