《实战Java虚拟机:JVM故障诊断与性能优化 (第2版)》
第三章 常用的 JVM 参数
3.1. 掌握跟踪调试参数 - 一切运行都有迹可循
参数类型 参数 作用 备注 GC 参数 - JVM 提供了一些跟踪系统状态的参数,使用给定的参数执行 JVM,就可以在系统运行时打印相关日志,用于问题分析 日志跟踪参数 - 如果垃圾回收频繁,或者占用了太长的 CPU 时间,就需要一些跟踪参数来进一步甄别垃圾回收的效率和效果 - -XX:+PrintGC
使用该参数后启动 JVM 后,只要遇到 GC,就会打印 GC 日志 (在 JDK9、JDK10 中建议使用 -Xlog:gc);JDK9、JDK10 默认使用 G1 作为垃圾回收器,使用参数 -Xlog:gc 来打印 GC 日志 - -XX:+PrintGCDetails
打印更加详细的 GC 信息;该参数还会使 JVM 在退出前打印堆的详细信息,详细信息描述了当前堆的各个区间的使用情况 (在 JDK9、JDK10 中建议使用 -Xlog:gc*) - -XX:+PrintHeapAtGC
打印更全面的堆信息;在每次 GC 前、后分别打印堆的信息 (考虑到兼容性,从 JDK9 开始已经删除此参数,查看堆信息可以使用 VisualVM) - -XX:+PrintGCTimeStamps
打印 GC 发生的时间;该参数会在每次 GC 时,额外输出 GC 发生的时间,该输出时间为 JVM 启动后的时间偏移量 (在 JDK9、JDK10 中使用 -Xlog:gc* 已经默认打印出时间) - -XX:+PrintGCApplicationConcurrentTime
打印应用程序的执行时间 - -XX:+PrintGCApplicationStoppedTime
打印应用程序由于 GC 而产生的停顿时间 - -XX:+PrintReferenceGC
打印系统内的软引用、弱引用、虚引用和 Finallize 队列 (考虑到兼容性,从 JDK9 开始已经删除此参数,查看堆信息可以使用 VisualVM) - -Xloggc:log/gc.log
在当前目录的 log 文件夹下的 gc.log 文件中记录所有的 GC 日志 (在 JDK9、JDK10 中建议使用 -Xlog:gc:log/gc.log) 类加载/卸载跟踪参数 - 跟踪运行时动态生成(动态代理、AOP 等技术生成的类)的比较隐蔽的类 - -verbose:class
跟踪类的加载/卸载 (在 JDK9、JDK10 中建议使用 -Xlog:class+load=info) - -XX:+TraceClassLoading
跟踪类的加载 (在 JDK9、JDK10 中建议使用 -Xlog:class+load=info) - -XX:+TraceClassUnloading
跟踪类的卸载 (在 JDK9、JDK10 中建议使用 -Xlog:class+unload=info) - -XX:+PrintClassHistogram
在运行时打印、查看系统中类的分布情况 在 Java 的控制台按下 Ctrl+Break 组合键,控制台上就会显示当前的类信息柱状图 系统参数 - 可以获取当前系统的实际运行参数 - -XX:+PrintVMOptions
可以在程序运行时打印 JVM 接收到的命令行显示参数 - -XX:+PrintCommandLineFlags
可以打印传递给 JVM 的显示和隐式参数 隐式参数未必是通过命令行直接给出的,它可能是在 JVM 启动时自行设置的 - -XX:+PrintFlagsFinal
打印所有的系统参数的值 开启这个参数后,JVM 可能会产生 500 多行输出,每一行为一个配置参数及其当前取值
3.2. 堆的配置参数 - 让性能飞起来
1.当 Java 进程启动时,JVM 就会分配一块初始堆空间,可以使用参数 -Xms 指定这块空间的大小。一般来说,JVM 会尽可能维持在初始堆空间的范围内运行。但是如果初始堆空间耗尽,JVM 将会对堆空间进行扩展,其扩展上限为最大堆空间,最大堆空间可以使用参数 -Xmx 指定。
类型 配置参数 说明 备注 整个堆 - - - - -Xmx
设置最大堆 - -Xms
设置初始堆 在实际工作中,可以直接将初始堆与最大堆设置为相等,这样的好处是,可以减少程序运行时进行垃圾回收的次数,从而提高程序的性能 新生代 - - - - -Xmn
设置新生代的大小 设置一个较大的新生代会减少老年代的大小,这个参数对系统性能及 GC 行为有很大的影响。新生代的大小一般设置为整个堆空间的 1/3 到 1/4。 - -XX:SurvivorRatio
设置新生代中 eden 区和 from/to 区的比例 含义为:-XX:SurvivorRatio=eden/from=eden/to - - - 不同的堆分布情况堆系统会产生一定影响。在实际工作中,应该根据系统的特点做合理的设置,基本策略是:尽可能将对象预留在新生代,减少老年代的次数。 - -XX:NewRatio
设置新生代和老年代的比例 -XX:NewRatio=老年代/新生代 堆溢出处理参数 - - - - -XX:+HeapDumpOnOutOfMemoryError
可以在内存溢出时导出整个堆的信息 和它配合使用的还有 -XX:HeapDumpPath - -XX:HeapDumpPath
可以指定导出堆的存放路径 - - -XX:OnOutOfMemoryError
可以在发生错误时执行一个脚本文件。该文件可以用于奔溃的程序自救、报警或者通知,也可以帮助开发人员获取更多的系统信息,如完整的线程转存(即 Thread Dump 或者 Core Dump)文件 “-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p”
3.3. 非堆内存的参数配置 - 别让性能有缺口
除了堆内存,JVM 还有一些内存用于方法区、线程栈和直接内存。它们与堆内存是相对独立的。与堆内存相比,虽然这些内存空间和应用程序本身的关系可能不那么密切,但是从系统层面看,有效、合理地配置这些内存参数,对系统的性能和稳定也有着重要作用。
类型 配置参数 说明 备注 方法区 - 主要存放类的元信息 - - -XX:PermSize
配置初始的永久区大小 在 JDK1.6 和 JDK1.7 等版本中 - -XX:MaxPermSize
配置最大永久区大小 在 JDK1.6 和 JDK1.7 等版本中 - -XX:MaxMetaspaceSize
指定永久区的最大可用值 从 JDK1.8 开始,永久区被彻底删除,使用了新的元数据区存放类的元数据。在默认情况下,元数据区只受系统可用内存的限制 栈 - 每个线程私有的内存空间 - - -Xss
指定线程的栈大小 直接内存 - 在 NIO 被广泛使用后,成为 Java 程序中非常重要的组成部分。直接内存跳过了 Java 堆,使 Java 程序可以直接访问原生堆空间 直接内存适合申请次数较少、访问较频繁的场合 - -XX:MaxDirectMemorySize
设置最大可用直接内存。如果不设置,默认值为最大堆空间,即 -Xmx 的值 当直接内存使用量达到 -XX:MaxDirectMemorySize 时,就会触发垃圾回收,如果垃圾回收不能释放足够的空间,直接内存溢出依然会引起系统的 OOM。
3.4. JVM 的工作模式 - Client 和 Server 二选一
目前 JVM 支持 Client 和 Server 两种运行模式。使用参数 -client 可以指定使用 Client 模式,使用参数 -server 可以指定使用 Server 模式。在默认情况下,JVM 会根据当前计算机系统环境自动选择运行模式。使用 -version 参数可以查看当前模式。
模式 优点 缺点 适用场景 Client 较 Server 模式启动速度快 较 Server 模式性能较差 适用于运行时间不长、追求启动速度的用户界面程序 Server 启动时会尝试收集更多的系统性能信息,使用更复杂的优化算法对程序进行优化;当系统完全启动并进入运行稳定期后,执行速度会远远快于 Client 模式 启动比较慢 适用于后台长期运行的系统;64位系统中 JVM 更倾向于使用 Server 模式
类型 配置参数 说明 备注 - -XX:+PrintFlagsFinal
JVM 在 Server 模式和 Client 模式下的各种参数可能会有很大的不同。查看给定参数的默认值