【问题标题】:Impact of setting -XX:+DisableExplicitGC when NIO direct buffers are used使用 NIO 直接缓冲区时设置 -XX:+DisableExplicitGC 的影响
【发布时间】:2015-10-02 17:31:32
【问题描述】:

我们正在构建一个具有激进性能 SLA 的 Web 应用程序,由于 System.gc() 调用导致 JVM 出去吃午饭,这些 SLA 会定期被违反。我们进行了一些调试,并确定在所有情况下,调用 System.gc() 的都是内部应用服务器代码。这在应用服务器启动或应用程序部署时会发生几次,我们并不关心。但是,System.gc() 也会在应用启动并通过内部应用服务器调用 NIO 类运行时定期触发。以下是我们能够捕获此事件的堆栈跟踪:

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.<init>(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])
....

是否有人知道如果我们通过启用 -XX:+DisableExplicitGC 关闭对 System.gc() 的调用会产生什么影响(或者实际上在我们的情况下通过设置 -Xdisableexplicitgc 因为我们在 IBM 上运行 Websphere JRE,它做同样的事情)?我们当然不想造成内存泄漏。我无法找到直接参考为什么 NIO 中的 System.gc() 调用实际上是必要的,也没有代码注释专门解决它在 JDK 代码中出现的位置:http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/4a1e42601d61/src/share/classes/java/nio/Bits.java

如果由于使用 NIO 而完全禁用 System.gc() 是个坏主意,那么至少我们可以做些什么来降低调用它的频率吗?看起来我们可以设置 -XX:MaxDirectMemorySize,但这似乎只会设置分配内存量的上限,并且可能会产生不利影响。

【问题讨论】:

  • 你用的是哪个 GC?
  • 我们在 IBM JVM 上使用 gencon GC 策略。 (如果您不熟悉 IBM JVM 的特性,gencon 策略与 Hotspot 上的 CMS 收集器非常相似。)
  • 在这种情况下,确保并发循环足够频繁地运行,以便可以回收符合 GC 条件的缓冲区也可以完成这项工作

标签: java garbage-collection nio


【解决方案1】:

禁用显式 GC 不会阻止缓冲区以及它们持有的本机内存被收集。但它可能会延迟很长一段时间的收集。

这意味着直接缓冲区分配的内存在被收集之前可能会累积很长时间。从长远来看,这并不是真正的泄漏,但会增加峰值内存使用量。

http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/4a1e42601d61/src/share/classes/java/nio/Bits.java

据我了解,当达到reserveMemory 限制时,System.gc() 调用可以释放缓冲区。保留请求的数量后,ByteBuffer.allocateDirect 将调用 Unsafe.allocateMemory,如果尝试 mmap 失败,Unsafe.allocateMemory 可能会执行自己的 GC 调用,这不应受到DisableExplicitGC 的影响。

我们至少可以做些什么来减少调用它的频率吗?

只有在达到MaxDirectMemorySize 限制时才会调用它。如果您可以调整您的 GC 或应用程序代码,使其满足以下选项之一:

  • 它使用一组固定的缓冲区(-> 永远不会超过限制)
  • 缓冲区被提早收集(短期缓冲区 -> 在年轻 GC 中死亡)
  • 在直接缓冲区空间用完之前定期收集老年代
  • 使用堆缓冲区而不是直接缓冲区

那么System.gc() 就不需要调用了。

在热点上还存在一个ExplicitGCInvokesConcurrent 选项。也许 IBM 的 VM 也有类似的东西。

【讨论】:

  • 非常感谢!我们是否也可以增加 -XX:MaxDirectMemorySize 的设置以延迟我们达到这个限制并且 System.gc() 会被调用?查看 OpenJDK 的 v7,如果在 MaxDirectMemorySize 阈值以下没有足够的可用直接内存,则会引发 OOM 错误:link。鉴于此,我想完全禁用 System.gc() 是个坏主意,而是应该使用您上面建议的 GC 调整技术来延迟或避免它。
  • 是的,您可以这样做,但我没有介绍该选项,因为您自己已经提到过。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-12
  • 1970-01-01
  • 1970-01-01
  • 2016-07-04
  • 1970-01-01
相关资源
最近更新 更多