关于 JVM 命令行标志您不知道的 5 件事

简介: Java™ 虚拟机有数百个命令行选项,被经验丰富的开发人员用来调优 Java 运行时。本文中,您将学习如何监控和记录编译器性能、禁用显式垃圾收集(System.gc();)、扩展 JRE 等等。 
JVM 是多数开发人员视为理所当然的 Java 功能和性能背后的重负荷机器。然而,我们很少有人能理解 JVM 是如何进行工作的 — 像任务分配和垃圾收集、转动线程、打开和关闭文件、中断和/或 JIT 编译 Java 字节码,等等。 
不熟悉 JVM 将不仅会影响应用程序性能,而且当 JVM 出问题时,尝试修复也会很困难。 
本期 5 件事 系列 将介绍一些命令行标志,您可以使用它们来诊断和调优您的 Java 虚拟机性能。 
1. DisableExplicitGC 
我已记不清有多少次用户要求我就应用程序性能问题提供咨询了,其实只要跨代码快速运行 grep,就会发现清单 1 所示的问题 — 原始 java 性能反模式: 

清单 1. System.gc(); 

                                // We just released a bunch of objects, so tell the stupid// garbage collector to collect them already!System.gc();

显式垃圾收集是一个 非常糟糕的主意 — 就像将您和一个疯狂的斗牛犬锁在一个电话亭里。尽管调用的语法是依赖实现的,但如果您的 JVM 正在运行一个分代的垃圾回收器(大多数是) System.gc(); 强迫 VM 执行一个堆的 “全部清扫”,虽然有的没有必要。全部清扫比一个常规 GC 操作要昂贵好几个数量级,这只是个简单数学问题。 
您可以不把我的话放在心上 — Sun 的工程师为这个特殊的人工错误提供一个 JVM 标志;  -XX:+DisableExplicitGC 标志自动将  System.gc() 调用转换成一个空操作,为您提供运行代码的机会,您自己看看  System.gc() 对于整个 JVM 执行有害还是有利。 

回页首 
2. HeapDumpOnOutOfMemoryError 
您有没有经历过这样的情况:JVM 不能使用,不断抛出  OutOfMemoryError,而您又不能为自己创建调试器来捕获它或查看出现了什么问题?像这类偶发和/或不确定的问题,通常使开发人员发疯。 
买者自负并不是任何 VM 都支持所有命令行标志,Sun/Oracle 的 VM 除外。查明一个标志是否被支持的最好方法是试用它,看它是否正常工作。倘若这些标志在技术上是不支持的,那么,使用它们您要承担全部责任。如果这些标志中的任何一个使您的代码、您的数据、您的服务器或您的一切消失得无影无踪,我、Sun/Oracle 和 IBM® 都将不负责任。为以防万一,建议先在虚拟(非常生产)环境中实验。 


在这个时刻您想要的是,在 JVM 消亡之际捕获堆的一个快照 — 正好  -XX:+HeapDumpOnOutOfMemoryError 命令可以完成这一操作。 
运行该命令通知 JVM 拍摄一个 “堆转储快照”,并将其保存在一个文件中以便处理,通常使用  jhat 实用工具(我在 上一篇文章 中介绍过)。您可以使用相应的  -XX:HeapDumpPath 标志指定到保存文件的实际路径。(不管文件保存在哪,务必确保文件系统和/或 Java 流程必须要有权限配置,可以在其中写入。) 

回页首 
3. bootclasspath 
定期将一个类放入类路径是很有帮助的,这类路径与库存 JRE 附带的类路径或者以某种方式扩展的 JRE 类路径略有不同。(新 Java Crypto API 提供商就是一个例子)。如果您想要扩展 JRE ,那么您定制的实现必须可以使用引导程序  ClassLoader,该引导程序可以加载  rt.jar 中的  java.lang.Object 及其所有相关文件。 
尽管您 可以 非法打开  rt.jar 并将您的定制实现或新数据包移入其中,但从技术上您就违反了您下载 JDK 时同意的协议了。 
相反,使用 JVM 自己的  -Xbootclasspath 选项,以及皮肤  -Xbootclasspath/p 和  -Xbootclasspath/a。 
-Xbootclasspath 使您可以设置完整的引导类路径(这通常包括一个对  rt.jar 的引用),以及一些其他 JDK 附带的(不是  rt.jar 的一部分)JAR 文件。 -Xbootclasspath/p 将值前置到现有 bootclasspath 中,并将  -Xbootclasspath/a 附加到其中。 
例如,如果您修改了库中的  java.lang.Integer,并将修改放在一个子路径  mods 下,那么  -Xbootclasspath/a mods 参数将新  Integer 放在默认的参数前面。 

回页首 
4. verbose 
对于虚拟的或任何类型的 Java 应用程序, -verbose 是一个很有用的一级诊断使用程序。该标志有三个子标志: gcclass 和  jni。 
开发人员尝试寻找是否 JVM 垃圾收集器发生故障或者导致性能低下,通常首先要做的就是执行  gc。不幸的是,解释  gc 输出很麻烦 — 足够写一本书。更糟糕的是,在命令行中打印的输出在不同的 Java 版本中或者不在不同的 JVM 中会发生改变,这使得正确解释变得更难。 
一般来说,如果垃圾收集器是一个分代收集器(多数 “企业级” VMs 都是)。某种虚拟标志将会出现,来指出一个全部清扫 GC 通路;在 Sun JVM 中,标志在 GC 输出行的开始以 “ [Full GC ...]” 形式出现。 
想要诊断  ClassLoader 和/或不匹配的类冲突, class 可以帮上大忙。它不仅报告类何时加载,还报告类从何处加载,包括到 JAR 的路径(如果来自 JAR)。 
jni 很少使用,除了使用 JNI 或本地库时。打开时,它将报告各种 JNI 事件,比如,本地库何时加载,方法何时弹回;再一次强调,在不同 JVM 版本中,输出会发生变化。 

回页首 
5. Command-line -X 
我列出了 JVM 中提供的我喜欢的命令行选项,但是还有一些更多的需要您自己发现,运行命令行参数  -X,列出 JVM 提供的所有非标准(但大部分都是安全的)参数 — 例如: 
  • -Xint,在解释模式下运行 JVM(对于测试 JIT 编译器实际上是否对您的代码起作用或者验证是否 JIT 编译器中有一个 bug,这都很有用)。
  • -Xloggc:,和 -verbose:gc 做同样的事,但是记录一个文件而不输出到命令行窗口。
JVM 命令行选项时常发生变化,因此,定期查看是一个好主意。甚至,您深夜盯着监控器和下午 5 点回家和妻子孩子吃顿晚饭,(或者在 Mass Effect 2 中消灭您的敌人,根据您的喜好),它们都是不一样的。 

回页首 
结束语 
在生产环境中,命令行标志不是为永久使用而设计的 — 事实上,除了您终止用来调优 JVM 垃圾收集器的标志,没有一个非标准命令行标记是专用于生产使用的。但是,作为工具来刺探在其他方面完全不透明的虚拟机的内部工作,是非常有用的。 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值