JVM 参数怎么调

基于 JVM 的语言和应用程序汗牛充栋,不仅限于 Java , 还有 Scala , JPython, JRuby。对于 JVM 的调优是每个JVM 应用开发者必需要了解的。

先回顾一下 JVM 的结构

JVM 结构

JVM 参数怎么调_第1张图片
JVM structure

堆内部的分代

  • 年轻代 Young Generation: 一般分为伊甸园 Eden 和幸存区 Survivor(通过分为两个区S0, S1), 新创建的对象放在Eden 区
  • 年老代 Old Generation
  • 永久代 Permanent Generation, Java 8 中改为 MetaSpace
JVM 参数怎么调_第2张图片
JVM Heap

JVM 参数调优

JVM 参数既多且杂,如何提纲挈领,避免挂一漏万呢?个人的想法是掌握原理,了解常用的参数就好了,以度量来驱动适用于你的应用程序的参数设置。

  • 1)设计:
    分析你的应用程序要求的吞吐量如何,它对于短暂的停顿是否敏感,从而了解到大约需要多大的内存,从而设置一个比较合理的参数,例如
    -Xms2048m
    -Xmx2048m
    -XX:MetaspaceSize=128m
    -XX:MaxMetaspaceSize=256m
    -XX:CompressedClassSpaceSize=256m
    -Xss1m
  • 2) 运行
    在程序运行期间设置如下参数来打印 GC 的运行时信息
-XX:+PrintGCDetails 
-XX:+PrintGCDateStamps 
-XX:+PrintHeapAtGC 
-XX:+PrintTenuringDistribution 
-XX:+PrintGCApplicationStoppedTime 
-XX:+PrintPromotionFailure 
-XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10 
-XX:GCLogFileSize=10M 
-Xloggc:./bin/../logs/gc.log
-XX:OnOutOfMemoryError="sh ./bin/oom-hander.sh"
  • 3) 监控
    重点监控如下指标

    • heap 堆内存使用情况
    • non-heap 非堆内存使用情况
    • gc pause 垃圾回收信息
    • oom 内存溢出错误
    • stackOverFlow 栈溢出错
  • 4)调优
    调整参数,以期更合理的内存分配和垃圾回收

常用JVM 调优参数

JVM 参数怎么调_第3张图片
  • JVM内存与垃圾收集
    • GC分类:
      • Minor GC
        • 也称 Scavenge GC, 收集新生代
        • 新对象在 Eden区申请空间失败时会触发
      • Major GC
        • 也称 Full GC, 收集新生代,年老代和永久代
        • 年老代或永久代被写满时会触发
    • GC算法:
      • 引用计数 Reference Counting
      • 标记清除 Mark-Sweep
      • 复制 Copying
      • 标记-压缩 Mark-Compact
    • JVM参数:
      • -Xmx=2048m 堆的最大值
      • -Xms=1024m 堆的初始值
      • -Xmn=128m 年轻代大小的值
      • -XX:newSize= 年轻代大小的初始值
      • -XX:maxNewSize= 年轻代大小的最大值
      • -XX:NewRatio= 年轻代与年老代的比例=年老代大小/年轻代大小
      • -XX:SurvivorRatio= 年轻代中的 Eden 区与 Survivor 区的比例=Eden区大小/(S1或S2区的大小)
      • -XX:MetaSpaceSize= 元空间(永久代)大小的初始值
      • -XX:MaxMetaSpaceSize= 元空间(永久代)大小的最大值
      • -Xss: 每个线程的堆栈大小
      • -XX:MaxDirectMemorySize= 直接内存大小的最大值
      • -XX:CompressedClassSpaceSize= 堆在小于32G时会将类信息放入 CompressedClassSpace, 即地址将64bit压缩成32bit
      • -XX:+AlwaysPreTouch 启动时预先初始化内存页,这样运行期就省去了初始化内存页这个步骤了
    • 指标
      • Throughput 吞吐量
        • the percentage of total time not spent in GC considered over long periods of time
      • Pauses 暂时时间
        • the times when an application appears unresponsive because GC is occurring
    • 分代 Generations 及适应的参数和回收算法
      • 永久代(元数据空间) MetaSpace
        • -XX:MetaspaceSize=128m
          • the initial amount of space(the initial high-water-mark)
        • -XX:MaxMetaspaceSize=256m
          • the maximum amount of space to be allocated for class metadata
        • -XX:MinMetaspaceFreeRatio=
          • min high-water-mark
        • -XX:MaxMetaspaceFreeRatio=
          • max high-water-mark
      • 年轻代 Young Generation
        • Serial
          • -XX:+UseSerialGC
        • ParNew
          • -XX:+UseParNew
        • Parallel Scavenge
          • -XX:+UseParallelGC
          • -XX:ParallelGCThreads=
      • 年老代 Old Generation
        • Serial Old
        • Parallel Old
        • CMS(Concurrent Mark Sweep)
          • -XX:+UseConcMarkSweepGC
        • G1(Gargage First)
          • -XX:+UseG1GC
          • -XX:MaxGCPaouseMillis=
          • -XX:ParallelGChreads=
    • Behavior-BasedTuning
      • 暂停时间目标 Pause Time Goal
        • -XX:MaxGCPauseMillis=
      • 吞吐量目标Throughput Goal
        • -XX:GCTimeRatio=
          • -XX:GCTimeRatio=19 sets a goal of 1/20th or 5% of the total time for GC
      • 体积目标 Footprint Goal
        • reduces the size of the heap until one of the goals(invariably the throughput goal) cannot be met
    • 调优策略 Tuning Strategy
      • 选择适合你的应用程序的吞吐量目标.
      • 选择适合的暂停时间目标,这点要和上面的吞吐量目标可能有冲突,要根据你的需要做出平衡

实例

以 Cassandra 为例,它是的一个高性能的分布式NOSQL 数据存储系统,它设置了如下 JVM 参数:

bin/java -Xloggc:./bin/../logs/gc.log 
-ea 
-XX:+UseThreadPriorities 
-XX:ThreadPriorityPolicy=42 
-XX:+HeapDumpOnOutOfMemoryError 
-Xss256k 
-XX:StringTableSize=1000003 
-XX:+AlwaysPreTouch 
-XX:-UseBiasedLocking 
-XX:+UseTLAB 
-XX:+ResizeTLAB 
-XX:+UseNUMA 
-XX:+PerfDisableSharedMem 
-Djava.net.preferIPv4Stack=true 
-XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC 
-XX:+CMSParallelRemarkEnabled 
-XX:SurvivorRatio=8 
-XX:MaxTenuringThreshold=1 
-XX:CMSInitiatingOccupancyFraction=75 
-XX:+UseCMSInitiatingOccupancyOnly 
-XX:CMSWaitDuration=10000 
-XX:+CMSParallelInitialMarkEnabled 
-XX:+CMSEdenChunksRecordAlways 
-XX:+CMSClassUnloadingEnabled 
-XX:+PrintGCDetails 
-XX:+PrintGCDateStamps 
-XX:+PrintHeapAtGC 
-XX:+PrintTenuringDistribution 
-XX:+PrintGCApplicationStoppedTime 
-XX:+PrintPromotionFailure -XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10 
-XX:GCLogFileSize=10M 
-Xms4096M 
-Xmx4096M 
-Xmn800M 
-XX:+UseCondCardMark 
-XX:CompileCommandFile=./bin/../conf/hotspot_compiler 
-javaagent:./bin/../lib/jamm-0.3.0.jar 
-Dcassandra.jmx.local.port=7199 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password 
-Djava.library.path=./bin/../lib/sigar-bin 
-XX:OnOutOfMemoryError=kill -9 %p 
-Dlogback.configurationFile=logback.xml 
-Dcassandra.logdir=./bin/../logs 
-Dcassandra.storagedir=./bin/../data 
-Dcassandra-foreground=yes 
-cp ./bin/../conf:./bin/../build/classes/main:./bin/../build/classes/thrift:...jar: org.apache.cassandra.service.CassandraDaemon

监控与观察

一般来说,比较常用的方法是通过 JMX 和 GC log 来度量你的 JVM 参数设置是是否合理,一旦发现异常或者 OOM 要马上采取措施进行调整

jstat -gcutil 1324
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00  15.10   7.84  97.24  92.57      2       0.017     1      0.034    0.051
  • S0: Survivor space 0 生存空间0利用率占该空间当前容量的百分比
  • S1: Survivor space 1 幸存者空间1利用率占该空间当前容量的百分比
  • E: Eden space 伊甸园空间利用率占空间当前容量的百分比
  • O: Old space 旧空间利用率占空间当前容量的百分比
  • M: Metaspace 元空间利用率占空间当前容量的百分比
  • CCS: Compressed class space 压缩的类空间利用率(以百分比表示)
  • YGC: Young generation GC 年轻代GC次数.
  • YGCT: Young generation GC Time年轻代GC耗时
  • FGC: Full GC 完全GC次数
  • FGCT: Full GC Time 完全GC耗时
  • GCT: Total GC Time 总GC耗时

关于 JVM 内存溢出的分析可以参考以前写的 内存溢出不可怕,手足无措才尴尬

参考资料

  • Book: Inside the Java Virtual Machine by Bill Venners
  • JVM options: https://www.oracle.com/java/technologies/javase/vmoptions-jsp.html

你可能感兴趣的:(JVM 参数怎么调)