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

红薯 发布于 2010/10/13 07:21
阅读 745
收藏 5

简介:
Java™ 虚拟机有数百个命令行选项,被经验丰富的开发人员用来调优 Java 运行时。本文中,您将学习如何监控和记录编译器性能、禁用显式垃圾收集(System.gc();)、扩展 JRE 等等。

JVM 是多数开发人员视为理所当然的 Java 功能和性能背后的重负荷机器。然而,我们很少有人能理解 JVM 是如何进行工作的 — 像任务分配和垃圾收集、转动线程、打开和关闭文件、中断和/或 JIT 编译 Java 字节码,等等。

不熟悉 JVM 将不仅会影响应用程序性能,而且当 JVM 出问题时,尝试修复也会很困难。

本期将介绍一些命令行标志,您可以使用它们来诊断和调优您的 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,而您又不能为自己创建调试器来捕获它或查看出现了什么问题?像这类偶发和/或不确定的问题,通常使开发人员发疯。

在这个时刻您想要的是,在 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 是一个很有用的一级诊断使用程序。该标志有三个子标志:gcclassjni

开发人员尝试寻找是否 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
V
V

看到老鼠发了编JVM方面,经过一段时间到网上撬下来的资料整理了一下跟着上了,希对从像我这样的小菜们有所帮助了:

 

A:JVM参数配置之heapsize

-Xmx
指定jvm的最大heap大小,:-Xmx2g(千万记住可是没有等号的哦)

-Xms
指定jvm的最小heap大小,:-Xms2g(千万记住可是没有等号的哦),高并发应用,建议和-Xmx一样,防止因为内存收缩/突然增大带来的性能影响,总之记住这遇见这两值配一样的数就OK

-Xmn
指定jvmNewGeneration的大小,:-Xmn256m。这个参数会很影响性能的哦,所以要配置好,如果你的程序需要比较多的临时内存,建议设置到512M,如果用的少,尽量降低这个数值,一般来说128256足以使用了,配置得小gc效率就越快,系统性能也就得到提高,一般情况下跟据系统配到能接受的下限就OK

-XX:PermSize=
指定jvmPermGeneration的最小值,:-XX:PermSize=32m。这个参数需要看你的实际情况。在生产环境中这个参数得需调试着才能拿到最准值,往往在应用中都会造成这一区域的内存溢出。

-XX:MaxPermSize=
指定(永久代)PermGeneration的最大值,:-XX:MaxPermSize=64m

-Xss
指定线程桟大小,:-Xss128k,一般来说,webx框架下的应用需要256K。如果你的程序有大规模的递归行为,请考虑设置到512K1M。这个需要全面的测试才能知道。不过,256K已经很大了。这个参数对性能的影响比较大的。分配得少也就意味着你能多弄几个线程出来,但还是得根据你的应用来拿拈了。

-XX:NewRatio=
指定jvmOldGenerationheapsizeNewGeneration的比例,在使用CMSGC的情况下此参数失效,:-XX:NewRatio=2

-XX:SurvivorRatio=
指定NewGenerationEdenSpace与一个SurvivorSpaceheapsize比例,-XX:SurvivorRatio=8,那么在总共NewGeneration10m的情况下,EdenSpace8m

-XX:MinHeapFreeRatio=
指定jvmheap在使用率小于n的情况下,heap进行收缩,Xmx==Xms的情况下无效,:-XX:MinHeapFreeRatio=30

-XX:MaxHeapFreeRatio=
指定jvmheap在使用率大于n的情况下,heap进行扩张,Xmx==Xms的情况下无效,:-XX:MaxHeapFreeRatio=70

-XX:LargePageSizeInBytes=
指定Javaheap的分页页面大小,:-XX:LargePageSizeInBytes=128m

B:JVM
参数配置garbagecollector

-XX:+UseParallelGC
指定在NewGeneration使用parallelcollector,并行收集,暂停appthreads,同时启动多个垃圾回收thread,不能和CMSgc一起使用.系统吨吐量优先,但是会有较长长时间的apppause,后台系统任务可以使用此gc

-XX:ParallelGCThreads=
指定parallelcollection时启动的thread个数,默认是物理processor的个数,

-XX:+UseParallelOldGC
指定在OldGeneration使用parallelcollector

-XX:+UseParNewGC
指定在NewGeneration使用parallelcollector,UseParallelGCgc的升级版本,有更好的性能或者优点,可以和CMSgc一起使用

-XX:+CMSParallelRemarkEnabled
在使用UseParNewGC的情况下,尽量减少mark的时间

-XX:+UseConcMarkSweepGC
指定在OldGeneration使用concurrentcmarksweepgc,gcthreadappthread并行(init-mark remarkpauseappthread).apppause时间较短,适合交互性强的系统,webserver

-XX:+UseCMSCompactAtFullCollection
在使用concurrentgc的情况下,防止memoryfragmention,liveobject进行整理,使memory碎片减少

-XX:CMSInitiatingOccupancyFraction=
指示在oldgeneration在使用了n%的比例后,启动concurrentcollector,默认值是68,:-XX:CMSInitiatingOccupancyFraction=70

-XX:+UseCMSInitiatingOccupancyOnly
指示只有在oldgeneration在使用了初始化的比例后concurrentcollector启动收集

C:
其他JVM参数配置

-XX:MaxTenuringThreshold=
指定一个对象(object)在经历了n次(新生代区里的GCyounggc后转移到oldgeneration(老生代区),linux64java6下默认值是15,此参数对于throughputcollector无效,:-XX:MaxTenuringThreshold=31

-XX:+DisableExplicitGC
禁止java程序中调用的fullgc,System.gc()的调用。一般都会要配此参数以提高系统性能。

-XX:+UseFastAccessorMethods
get,set方法转成本地代码


-XX:+PrintGCDetails
此参数用来打应垃圾收集的详细情况

-XX:+PrintGCTimeStamps
打应垃圾收集的时间分部情况

-XX:+PrintGCApplicationStoppedTime
打应垃圾收集时,GC时导致的系统停顿时间

D:几组GC对新旧代的回收方式列表: 

指定方式                                                  新生代GC方式              旧生代GC方式

 

-XX:+UseSerialGC                                         串行GC                     串行GC

 

-XX:+UseParallelGC                                     并行回收GC                 并行GC

 

-XX:+UseConeMarkSweepGC                      并行GC                     并发GC

 

-XX:+UseParNewGC                                   并行GC                      串行GC

 

-XX:+UseParallelOldGC                              并行回收GC                 并行GC

 

-XX:+ UseConeMarkSweepGC                  

-XX:+UseParNewGC                                  串行GC                     并发GC

 

不支持的组合                 1-XX:+UseParNewGC -XX:+UseParallelOldGC

                                    2-XX:+UseParNewGC -XX:+UseSerialGC

 

三种方式的拉圾回收总结:

串行收集:串行收集使用单线程处理所有垃圾回收工作,因为无需多线程交互,实现容易,而且效率比较高。但是,其局限性也比较明显,即无法使用多处理器的优势,适合单处理器机器。

 

并行收集:并行收集使用多线程处理垃圾回收工作,因而速度快,效率高。而且理论上CPU数目越多,就会越能体现出并行收集器的优势。

 

并发收集:相对于串行收集和并行收集而言,前面两个在进行垃圾回收工作时,需要暂停整个运行环境(即只有GC一个线程在跑,其它的弟兄们都得停下手头上的活来等着这兄弟执行完),因此,系统在垃圾回收时会有明显的暂停,而且暂停时间会因为堆越大而越长。

 

参考资料:http://developer.51cto.com/art/201009/227560.htm

             http://www.builder.com.cn/2007/1108/616837.shtml

-赵本山-
-赵本山-
有一个参数不明,请指教。 文中在B:JVM参数配置garbagecollector 参数名如下: -XX:+UseConcMarkSweepGC 文中在D:几组GC对新旧代的回收方式列表: 参数名如下: -XX:+UseConeMarkSweepGC 请问这个参数是**Conc***还是**Cone***
0
JavaGG
JavaGG

bootclasspath

这个牛B

返回顶部
顶部