Advanced Java-02c-JVM参数和性能

JVM的模式

关于JVM的类型和模式 - ImportNew

  • 使用java -version命令查看出当前虚拟机处于哪种类型模式: Server or Client
  • JVM启动时采用何种模式是在名为jvm.cfg的配置文件中配置的:
    • 在32位JDK中,jvm.cfg位置为:JAVA_HOME/jre/lib/i386/jvm.cfg
    • 在64位JDK中,jvm.cfg位置为:JAVA_HOME/jre/lib/amd64/jvm.cfg
  • Server 和 Client 的区别:

    These two systems are different binaries. They are essentially two different compilers (JITs)interfacing to the same runtime system. The client system is optimal for applications which need fast startup times or small footprints, the server system is optimal for applications where the overall performance is most important. In general the client system is better suited for interactive applications such as GUIs. Some of the other differences include the compilation policy,heap defaults, and inlining policy.
    Client JVM适合需要快速启动和较小内存空间的应用,它适合交互性的应用,比如GUI;而Server JVM则是看重执行效率的应用的最佳选择。不同之处包括:编译策略、默认堆大小、内嵌策略。

  • 使用java -X 可以看到Jvm工作模式 // JVM有以下几种模式:-Xint, -Xcomp, 和 -Xmixed

    • -Xint代表解释模式(interpreted mode),-Xint标记会强制JVM以解释方式执行所有的字节码
    • -Xcomp代表编译模式(compiled mode),与它(-Xint)正好相反,JVM在第一次使用时会把所有的字节码编译成本地代码,从而带来最大程度的优化
    • -Xmixed代表混合模式(mixed mode),前面也提到了,混合模式是JVM的默认工作模式。它会同时使用编译模式和解释模式。对于字节码中多次被调用的部分,JVM会将其编译成本地代码以提高执行效率;而被调用很少(甚至只有一次)的方法在解释模式下会继续执行,从而减少编译和优化成本

JVM相关日志

  • -XX:+HeapDumpOnOutOfMemoryError XX:HeapDumpPath=../ 开启jvm内存不足时生成dump文件, 指定位置
  • -XX:ErrorFile=/var/log/hs_err_pid.log jvm崩溃日志
  • -XX:+PrintGC -XX:+PrintGCDateStamps -Xloggc:../logs/gc.log 开启GC日志, 输出时间戳, 指定GC日志位置

JVM参数: -D -X -XX

查看当前JVM默认参数的命令: java -XX:+PrintFlagsFinal -version, 下面是需要注意的参数说明:

-D参数:

  • -D: JVM系统参数, 可以自定义, 在代码里通过System.getProperty("xxx")获取到
    • -Djava.ext.dirs=/path: -classpath参数只能指定jar包, 如果需要把某个目录的jar都包含进来, 可以使用-Djava.ext.dir=
    • -Dfile.encoding=UTF-8:
    • -Djava.io.tmpdir=/tmp: 在此路径下生成pid文件, jps命令读取此文件返回结果, 默认是/tmp/hsperfdata_<username>/目录下

-X参数:

  • -X: 设置JVM扩展参数, 非标准的, 不保证任何JVM都实现
    • -Xms512m: 堆的初始化大小,默认物理内存的1/64(<1GB),
    • -Xmx512m: 最大堆大小,物理内存的1/4(<1GB)
    • -Xss1m: 线程栈大小, JDK5.0以后每个线程堆栈大小为1M

-XX参数:

  • -XX: 不稳定的参数, 不推荐在生产环境中使用:

    • -XX:AutoBoxCacheMax : JAVA进程启动的时候,会加载rt.jar这个核心包的,rt.jar包里的Integer自然也是被加载到JVM中, VM在加载Integer这个类时,会优先加载静态的代码。当JVM进程启动完毕后, -128 ~ +127 范围的数字会被缓存起来,调用valueOf方法的时候,如果是这个范围内的数字,则直接从缓存取出。
      因此可以根据实际情况把AutoBoxCacheMax的值设置的更多一些: -XX:AutoBoxCacheMax=2000
    • -XX:+AlwaysPreTouch : JAVA进程启动的时候,虽然我们可以为JVM指定合适的内存大小,但是这些内存操作系统并没有真正的分配给JVM,而是等JVM访问这些内存的时候,才真正分配.
      这个参数可以让让操作系统在启动JVM时, 把内存真正的分配给JVM;
    • -XX:CMSInitiatingOccupancyFraction : 当老年代堆空间的使用率达到75%的时候就开始执行垃圾回收, CMSInitiatingOccupancyFraction默认值是92%,这个就太大了
      -XX:CMSInitiatingOccupancyFraction=75, 注意 CMSInitiatingOccupancyFraction 参数必须跟下面两个参数一起使用才能生效:

      -XX:+UseConcMarkSweepGC
      -XX:+UseCMSInitiatingOccupancyOnly
    • -XX:MaxTenuringThreshold 默认情况下, 这个值是15, 意思是 当新生代执行了15次 young gc后, 如果还有对象存活在Survivor区中,那么就可以直接将这些对象晋升到老年代.
      但是由于新生代使用copy算法,如果 Survivor区存活的对象太久的话, Survivor区存活的对象就越多, 这个就会影响copy算法的性能,使得 young gc停顿的时间加长,建议设置成6。
      有个例外的情况, 可能导致GC收集器 不按照MaxTenuringThreshold的值进行晋升,
      [动态年龄计算] :JVM遍历所有对象时,按照年龄从小到大对其所占用的大小进行累积,当累积的某个年龄大小超过了survivor区的一半时,取这个年龄和MaxTenuringThreshold中更小的一个值,作为新的晋升年龄阈值。例如age=2的所有对象占用了超过一半Survivor区大小, 那么晋升至老年代的age阈值会调整为2

    • -XX:ExplicitGCInvokesConcurrent 如果系统使用堆外内存,比如用到了Netty的DirectByteBuffer类,那么当想回收堆外内存的时候,需要调用System.gc(), 而这个方法将进行full gc,整个应用将会停顿,
      如果是使用CMS垃圾收集器,那么可以设置-XX:+ExplicitGCInvokesConcurrent, 来改变System.gc()的行为,让其从 full gc 变为 CMS GC,
      CMS GC 是并发收集的,且中间执行的过程中,只有部分阶段需要 STW;
    • -XX:PermSize : 设置持久代(perm gen)初始值 物理内存的1/64, 例 XX:PermSize=512M
    • -XX:MaxPermSize 设置持久代最大值 物理内存的1/4
    • -XX:SurvivorRatio: Eden和Survivor的大小比例, -XX:SurvivorRatio=8表示 Eden:Survivor=8:1,这是默认值
    • -XX:NewRatio: 老年代:年轻代 的比值, The default NewRatio for the Server JVM is 2: the old generation occupies 2/3 of the heap while the new generation occupies 1/3
      如果Young GC很频繁, 可以降低老年代的比例: -XX:NewRatio=1;
    • 注意:-Xmn的优先级比-XX:NewRatio高,若-Xmn已指定,则无需再按NewRatio的比例计算。生产环境中一般只需指定-Xmn
    • -XX:MaxTenuringThreshold: 控制进入老年前生存次数等, 如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率, 该参数只有在串行GC时才有效.
    • -XX:+DisableExplicitGC: 关闭System.gc() 这个参数需要严格的测试
    • -XX:+UseParallelGC: 选择垃圾收集器为并行收集器.此配置仅对年轻代有效
    • -XX:+UseParNewGC: 设置年轻代为并行收集
    • -XX:+UseParallelOldGC: 老年代垃圾收集方式为并行收集(Parallel Compacting)
    • -XX:+UseConcMarkSweepGC: 使用CMS内存收集
    • -XX:+PrintGC
    • -XX:+PrintGCDetails
    • -XX:+PrintGC:PrintGCTimeStamps
    • -XX:+HeapDumpOnOutOfMemoryError: 当JVM因内存不足崩溃时产生dump文件
    • -XX:ErrorFile=/var/log/hs_err_pid.log: JVM崩溃, 产生的日志位置

JVM参数最佳实践

@ref: hashcon 我所使用的生产 Java 17 启动参数 - 掘金

@Deprecated:

-Xmx4g -Xms4g -Xmn1G
-XX:+UseParNewGC -XX:UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
-verbose:gc -XX:+printGCDetails -XX:+PrintGCTimeStamps -Xloggc:${HBASE_HOME}/logs/gc-${hostname}-hbase.log