在JVM上启用逃逸分析的经验分享

7
我刚刚在Solaris上运行了一个Scala应用程序,该程序有相当多的Actor(20,000个),并启用了JDK6-u18 VM(Java虚拟机)上的-XX:+DoEscapeAnalysis选项,但是结果令人失望。通常情况下,该应用程序可以使用256Mb的堆内存,但会生成大量垃圾。在其稳态时,它:
- 花费10%的时间进行垃圾回收 - 在不到30秒的时间内生成超过150Mb的垃圾,然后被GC回收
我认为逃逸分析可能有所帮助,因此我启用了该选项并重新运行了应用程序。我发现应用程序变得越来越无法清除所收集的垃圾,直到最终似乎花费了整个时间进行垃圾回收,并且应用程序在其完全分配的情况下“停滞不前”。
此时,我应该说一下,该应用程序没有抛出OutOfMemoryError,这让我感到意外。也许JConsole(我用于执行分析)在启用此选项时无法正确显示GC统计信息(我并不确信)?
然后,我删除了该选项并重新启动,应用程序又恢复了“正常”!有人知道可能发生了什么吗?
3个回答

8

1 逃逸分析是否在JConsole中显示为已启用?您需要确保使用-server选项运行VM。我假设您已经使其工作,但我只是想检查一下。

2 我认为逃逸分析对Scala Actors的情况不会有帮助。如果您执行以下操作,则可能会获得很大的收益:

def act():Unit = {
   val omgHugeObject = new OMGHugeObject();
   omgHugeObject.doSomethingCrazy();
 }

在上面的例子中,逃逸分析将使得omgHugeObject可以在栈上分配而不是堆上分配,从而不会产生垃圾。我认为逃逸分析不太可能对演员有所帮助。它们的引用将始终“逃逸”到演员子系统。
3 您是否使用最新版本的Scala?我相信最近的一个版本修复了一个内存泄漏问题。这甚至导致Lift推出了自己的Actor库,您可以尝试一下。
4 您可以尝试G1垃圾收集器,您可以通过以下方式启用它: -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

如果是对象从一个线程传输到另一个线程,那么不仅堆栈分配将变得不可能,我想 Thread Local Allocation Buffers (TLAB) 也会出现问题。我相信 JRockit JVM 在其线程本地内存行为方面甚至更加积极。 - Tom Hawtin - tackline
我并不指望逃逸分析能够帮助演员本身,但是应用程序中堆栈上发生了大量其他隐式转换,这些可以被省略。我只是希望在GC开销方面有所改善! - oxbow_lakes
G1的问题在于使用JConsole无法真正看到发生了什么。 - oxbow_lakes
是的 - 堆分析已启用。我不需要 -server,因为我在运行太阳能怪物上,所以 JVM 默认是服务器版的。是的,我正在使用 Scala 2.7.7。 - oxbow_lakes
逃逸分析已被禁用:https://dev59.com/D0vSa4cB1Zd3GeqPgbOe#2183956 - Seun Osewa
显示剩余2条评论

6

来自jdk-u18发布说明

请注意,基于逃逸分析的优化(-XX:+DoEscapeAnalysis)在6u18中被禁用。这个选项将在未来的Java SE 6更新中恢复。


1
是的,在Java 6u23及更高版本中,默认启用了此功能(请参见http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html)。 - Andy Lynch

3

我建议您尝试增加新生代大小,例如-XX:NewSize=96M XX:NewRatio=3。使用JDK中包含的JVisualVM,并使用Visual GC插件观察年轻代和老年代的利用情况。


是的 - 我尝试过这个,但几乎没有任何区别。我尝试了从1到4的比率。 - oxbow_lakes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接