在生产环境中设置-XX:+ DisableExplicitGC:可能出现什么问题?

16 浏览
0 Comments

在生产环境中设置-XX:+ DisableExplicitGC:可能出现什么问题?

我们刚刚开了一次会,讨论了一个用于计算保险费率的Web应用程序中的一些性能问题。这个计算是由一个C/C++模块实现的,该模块也被其他软件包使用。为了将其作为Web服务使用,实现了一个Java包装器,该包装器公开了基于XML的接口,并通过JNI调用了C/C++模块。

测量结果显示,Java部分的每个计算需要花费几秒钟的时间。因此,我的第一个建议是在VM中启用垃圾回收日志记录。我们可以立即看到许多停止-全局GC,开发Java部分的人告诉我们他们在多个情况下使用了System.gc()\"以确保在使用后释放内存\".

好的,我不会对这个声明做进一步的解释... 😉

然后,我们在VM的参数中添加了上述的-XX:+DisableExplicitGC,并重新运行了测试。这使每次计算节省了约5秒。

由于在我们的发布流程中,我们无法通过删除所有这些System.gc()调用来更改代码,因此我们考虑在生产中添加-XX:+DisableExplicitGC,直到可以创建新的Jar文件。

现在的问题是:这样做会有任何风险吗?关于我唯一能想到的事情就是重新部署时Tomcat内部使用System.gc(),但这只是一个猜测。还有其他的危险吗?

admin 更改状态以发布 2023年5月21日
0
0 Comments

我一直在尝试解决这个问题,根据我找到的所有信息,显然存在一定的风险。根据@millimoose在原帖中的评论以及https://bugs.openjdk.java.net/browse/JDK-6200079,如果正在使用NIO直接缓冲区,设置-XX:+DisableExplicitGC可能是一个坏主意。它似乎被用于Websphere 8.5应用服务器的内部实现。我在调试过程中捕获的堆栈跟踪如下:

3XMTHREADINFO      "WebContainer : 25" J9VMThread:0x0000000006FC5D00, j9thread_t:0x00007F60E41753E0, java/lang/Thread:0x000000060B735590, state:R, prio=5
3XMJAVALTHREAD            (java/lang/Thread getId:0xFE, isDaemon:true)
3XMTHREADINFO1            (native thread ID:0x1039, native priority:0x5, native policy:UNKNOWN)
3XMTHREADINFO2            (native stack address range from:0x00007F6067621000, to:0x00007F6067662000, size:0x41000)
3XMCPUTIME               CPU usage total: 80.222215853 secs
3XMHEAPALLOC             Heap bytes allocated since last GC cycle=1594568 (0x1854C8)
3XMTHREADINFO3           Java callstack:
4XESTACKTRACE                at java/lang/System.gc(System.java:329)
4XESTACKTRACE                at java/nio/Bits.syncReserveMemory(Bits.java:721)
5XESTACKTRACE                   (entered lock: java/nio/Bits@0x000000060000B690, entry count: 1)
4XESTACKTRACE                at java/nio/Bits.reserveMemory(Bits.java:766(Compiled Code))
4XESTACKTRACE                at java/nio/DirectByteBuffer.(DirectByteBuffer.java:123(Compiled Code))
4XESTACKTRACE                at java/nio/ByteBuffer.allocateDirect(ByteBuffer.java:306(Compiled Code))
4XESTACKTRACE                at com/ibm/ws/buffermgmt/impl/WsByteBufferPoolManagerImpl.allocateBufferDirect(WsByteBufferPoolManagerImpl.java:706(Compiled Code))
4XESTACKTRACE                at com/ibm/ws/buffermgmt/impl/WsByteBufferPoolManagerImpl.allocateCommon(WsByteBufferPoolManagerImpl.java:612(Compiled Code))
4XESTACKTRACE                at com/ibm/ws/buffermgmt/impl/WsByteBufferPoolManagerImpl.allocateDirect(WsByteBufferPoolManagerImpl.java:527(Compiled Code))
4XESTACKTRACE                at com/ibm/io/async/ResultHandler.runEventProcessingLoop(ResultHandler.java:507(Compiled Code))
4XESTACKTRACE                at com/ibm/io/async/ResultHandler$2.run(ResultHandler.java:905(Compiled Code))
4XESTACKTRACE                at com/ibm/ws/util/ThreadPool$Worker.run(ThreadPool.java:1864(Compiled Code))
3XMTHREADINFO3           Native callstack:
4XENATIVESTACK               (0x00007F61083DD122 [libj9prt26.so+0x13122])
4XENATIVESTACK               (0x00007F61083EA79F [libj9prt26.so+0x2079f])
....

关于在使用NIO直接字节缓冲区时设置-XX:+DisableExplicitGC的全部后果尚不清楚(这会引入内存泄漏吗?),但至少存在一定的风险。如果您使用的是除Websphere之外的应用服务器,则可能需要验证应用服务器本身是否在通过NIO调用System.gc()之后禁用它。我们有一个相关的问题,希望能在此得到一些有关NIO库确切影响的澄清:Impact of setting -XX:+DisableExplicitGC when NIO direct buffers are used

顺便说一句,Websphere似乎还在启动过程中手动调用System.gc()多次,通常在应用服务器启动后的前几秒内两次,以及在1-2分钟内第三次(可能是在部署应用程序时)。在我们的情况下,这就是我们首先开始调查的原因,因为似乎所有的System.gc()调用都来自应用服务器,从未来自我们的应用程序代码。

还应该注意的是,除了NIO库外,JDK的分布式垃圾收集内部实现也会调用System.gc():Unexplained System.gc() calls due to Remote Method Invocation System.gc() calls by core APIs

至于启用-XX:+DisableExplicitGC是否也会对RMI DGC造成破坏,我也不太清楚。我找到的唯一一个涉及此事的参考文献是上面的第一个参考文献,其中指出:

"然而,在大多数情况下,定期的GC活动就足以有效地进行DGC"

这个“在大多数情况下”的限定词对我来说听起来有些含糊,因此,再一次,似乎关掉所有System.gc()调用至少存在一定的风险,如果可能,最好修复您代码中的这些调用,仅在必要情况下才完全禁用它们。

0
0 Comments

-XX:+DisableExplicitGC标志设置为修复“stop-the-world” GC事件并不孤单。不幸的是(尽管文档中有免责声明),许多开发人员决定在何时收集内存方面比JVM更明智,并引入了此类问题。

我知道许多情况下,-XX:+DisableExplicitGC可以改善生产环境,而没有任何负面影响。

安全的做法是在压力测试环境下使用该标志运行当前生产代码,并执行正常的QA周期。

如果无法这样做,我建议在大多数情况下,设置标志的风险小于不设置标志的成本。

0