使用NIO直接缓冲区时设置-XX:+ DisableExplicitGC的影响

时间:2015-10-02 17:31:32

标签: java garbage-collection nio

我们正在构建一个具有积极性能SLA的Web应用程序,由于JVM因System.gc()调用而外出午餐,因此会定期违反这些SLA。我们做了一些调试,并确定在所有情况下它都是调用System.gc()的内部应用服务器代码。在app服务器启动或部署应用程序时会发生这种情况,我们并不关心。但是,当应用程序启动并通过内部应用程序服务器调用NIO类时,也会定期触发System.gc()。这是我们能够捕获此事件的堆栈跟踪:

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来关闭对System.gc()的调用会有什么影响:+ DisableExplicitGC(或者实际上是在我们的情况下通过设置-Xdisableexplicitgc,因为我们在IBM上运行Websphere JRE,它做同样的事情)?我们当然不希望创建内存泄漏。我无法找到直接引用为什么在NIO中调用System.gc()实际上是必要的,并且在JDK代码中没有专门解决它的代码注释:{{3 }}

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

1 个答案:

答案 0 :(得分:3)

禁用显式GC不会阻止缓冲区,从而阻止收集它们的本机内存。但它可能会延迟收藏很长时间。

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

  

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

据我所知,System.gc()调用是在reserveMemory限制被命中时释放缓冲区。保留所请求的金额ByteBuffer.allocateDirect后,如果尝试mmap失败,则会调用可能会执行自己的GC调用的Unsafe.allocateMemory,该调用不应受DisableExplicitGC的影响。

  

至少我们可以做些什么来降低它被调用的频率?

只有在MaxDirectMemorySize限制被命中时才会调用它。如果您可以调整GC或应用程序代码,使其符合以下选项之一:

  • 它使用一组固定的缓冲区( - &gt;绝不会超出限制)
  • 早期收集缓冲液(短期缓冲液 - >在年轻GC中死亡)
  • 在直接缓冲区空间耗尽之前定期收集旧代
  • 使用堆缓冲区而不是直接缓冲区

然后System.gc()电话不再有必要。

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