`

转:Java SE 6 Hotspot [TM] 虚拟机垃圾回收调优 2

    博客分类:
  • JVM
阅读更多
7.10 测量

下面是使用-verbose:gc和-XX:+PrintGCDetails参数时,并发垃圾收集器的输出,一些小细节已经被去掉了。注意,并发垃 圾收集器的输出里掺杂着小回收的输出;典型情况下,很多小回收会发生在并发收集周期之中。其中的CMS-initial-mark表征了一个并发垃圾回收 周期的开始。CMS-concurrent-mark: 标志着并发标记阶段的完成,而CMS-concurrent-sweep则标志着并发清除阶段的完成。之前没有提到过的预清除阶段以CMS- concurrent-preclean为标志。预清除可以和重标记阶段CMS-remark的准备工作同时运行。最后一个阶段是CMS- concurrent-reset,这是下一个并发收集周期的准备工作。

[GC [1 CMS-initial-mark: 13991K(20288K)] 14103K(22400K), 0.0023781 secs][GC [DefNew: 2112K->64K(2112K), 0.0837052 secs] 16103K->15476K(22400K), 0.0838519 secs]...[GC [DefNew: 2077K->63K(2112K), 0.0126205 secs] 17552K->15855K(22400K), 0.0127482 secs][CMS-concurrent-mark: 0.267/0.374 secs][GC [DefNew: 2111K->64K(2112K), 0.0190851 secs] 17903K->16154K(22400K), 0.0191903 secs][CMS-concurrent-preclean: 0.044/0.064 secs][GC [1 CMS-remark: 16090K(20288K)] 17242K(22400K), 0.0210460 secs][GC [DefNew: 2112K->63K(2112K), 0.0716116 secs] 18177K->17382K(22400K), 0.0718204 secs][GC [DefNew: 2111K->63K(2112K), 0.0830392 secs] 19363K->18757K(22400K), 0.0832943 secs]...[GC [DefNew: 2111K->0K(2112K), 0.0035190 secs] 17527K->15479K(22400K), 0.0036052 secs][CMS-concurrent-sweep: 0.291/0.662 secs][GC [DefNew: 2048K->0K(2112K), 0.0013347 secs] 17527K->15479K(27912K), 0.0014231 secs][CMS-concurrent-reset: 0.016/0.016 secs][GC [DefNew: 2048K->1K(2112K), 0.0013936 secs] 17527K->15479K(27912K), 0.0014814 secs]

初始标记停顿在典型情况下比小回收的停顿时间还要小。而如上例所示,并发阶段(并发标记、并发预清除和并发清除)通常会比小回收长很多。不过注意, 应用并没有在这些并发阶段中停顿下来。重标记停顿通常和一个小回收的长度相当。重标记停顿挥手道应用的某些特征(如高对象修改频率可能会增加这个停顿)和 上一次小回收的时间(即,更多的年轻代对象可能会增加这个停顿)的影响。

8. 其他考虑

8.1 永久代尺寸

在大部分应用中,永久代对于垃圾回收性能没有显著的影响。不过,一些应用会动态的生成与加载很多类;比如,一些 JavaServer Pages(JSP)页面的实现。这些应用可能需要很大的永久代去存放一些多余的类。如果这样的话,最大永久代的尺寸可以用命令行参数 -XX:MaxPermSize=<N>来增大。

8.2 Finalization; Weak, Soft and Phantom References

一些应用使用 finalization 和 weak, soft, phantom 引用与垃圾收集器交互。这些特征可以 Java 语言层带来性能影响。一个例子是通过 finalization 来关闭文件描述符,这会导致一个外部资源依赖于垃圾收集器。以来垃圾收集器来管理内存之外的资源是个坏主意。

参考资料章节中的文章深度讨论了一些finalization的常见错误和用来避免这些错误的技术。

8.3 显式垃圾回收

应用程序和垃圾回收器的另一个交互途径是显式调用 System.gc() 进行完整的垃圾回收。这回强制进行一次主回收,即使没有必要(也就是说一次小回收可能就足够了),所以应该避免这种情况。显式垃圾回收对性能的影响可以通 过使用 -XX:+DisableExplicitGC 进行比较来进行测量,这样虚拟机会无视 System.gc() 的。

最常见的显式调用垃圾回收的场景是 RMI 的分布式垃圾回收。使用 RMI 的应用会引用到其他虚拟机中的对象。在这种分布式应用的场景下,本地堆中的垃圾可能不能被回收掉,所以 RMI 会周期性强制进行完整的垃圾回收。这些回收的频率可以使用参数来控制。如

java -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 …

这里指定了垃圾回收每小时运行一次,而不是缺省的每分钟一次。不过,这可能会导致某些对象的清除消耗太长时间。这些参数可以被设置到高达Long.MAX_VALUE来让显式垃圾回收的间隔时间无限长,如果没有合适的DGC上限时间的话。

8.4 Soft References

Soft reference在虚拟机中比在客户集中存活的更长一些。其清除频率可以用命令行参数 -XX:SoftRefLRUPolicyMSPerMB=<N>来控制,这可以指定每兆堆空闲空间的 soft reference 保持存活(一旦它不强可达了)的毫秒数,这意味着每兆堆中的空闲空间中的 soft reference 会(在最后一个强引用被回收之后)存活1秒钟。注意,这是一个近似的值,因为 soft reference 只会在垃圾回收时才会被清除,而垃圾回收并不总在发生。

8.5 Solaris 8 替换 libthread

Solaris 8 操作系统提供了一个替代的线程库,libthread, 它将线程直接绑定成了轻量级进程(LWP)。有些应用能够从中极大获益,并潜在的对所有多线程应用都或多或少的有好处。下面的命令会为 java 启用替换的 libthread(BASH 格式)

LD_PRELOAD=/usr/lib/lwp/libthread.so.1export LD_PRELOADjava ...

这个方法仅对 Solaris 8 适用,因为对 Solaris 9 操作系统来说,这是缺省的,而 Solaris 10 中,这是惟一的线程库。

9. 相关资源

  1. HotSpot VM Frequently Asked Questions (FAQ)
  2. GC output examples 介绍了如何解释不同垃圾收集器的输出。
  3. How to Handle Java Finalization’s Memory-Retention Issues 介绍了一些容易犯的错误和避免他们的方法。
  4. Richard Jones and Rafael Lins, Garbage Collection: Algorithms for Automated Dynamic Memory Management, Wiley and Sons (1996), ISBN 0-471-94148-4

在本网站中,名词“Java Virtual Machine” 和“JVM” 都代表 Java 平台虚拟机。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics