如何解决使用NIO直接缓冲区时设置-XX:+ DisableExplicitGC的影响
禁用显式GC不会阻止缓冲区,因此不会阻止缓冲区保留的本地内存被收集。但这可能会拖延很长时间。
这意味着直接缓冲区分配的内存可能会在收集之前积累很长时间。从长远来看,这并不是真正的泄漏,但是它将增加峰值内存使用率。
http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/4a1e42601d61/src/share/classes/java/nio/Bits.java
据我了解,达到限制后,System.gc()
调用就会释放缓冲区reserveMemory
。预留请求量之后ByteBuffer.allocateDirect
会调用Unsafe.allocateMemory
它可能会做自己的呼叫模式,不应由受到影响disableExplicitGC
,如果尝试失败MMAP。
我们至少可以做些什么来降低其被调用的频率?
仅在达到MaxDirectMemorySize
限制时调用。如果您可以调整GC或应用程序代码,使其符合以下选项之一:
- 它使用一组固定的缓冲区(永远不会超出->限制)
- 尽早收集缓冲液(寿命短的缓冲液->在年轻的GC中死亡)
- 在直接缓冲区空间用完之前,定期收集旧一代
- 使用堆缓冲区而不是直接缓冲区
则System.gc()
无需通话。
在热点上,还存在一个ExplicitGCInvokesConcurrent
选项。也许IBM的VM具有类似的功能。
解决方法
我们正在构建具有积极性能SLA的Web应用程序,由于JVM由于System.gc()调用而无法正常工作,因此这些SLA经常遭到违反。我们已经进行了一些调试,并确定在所有情况下都是调用System.gc()的内部应用服务器代码。在应用服务器启动或部署应用程序时,这种情况会发生几次,我们并不在意。但是,当应用程序通过内部应用程序服务器启动和运行并调用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:+ DisableExplicitGC(或者实际上在我们的情况下是通过设置-
Xdisableexplicitgc来关闭对System.gc()的调用会造成的影响,因为我们正在IBM
JRE上运行Websphere,因此一样吗?我们当然不想造成内存泄漏。关于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,但这似乎只设置分配的内存量的上限,并且可能会产生不利影响。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。