当前位置: 首页 > 面试题库 >

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

闽涵蓄
2023-03-14
问题内容

我们正在构建具有积极性能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,但这似乎只设置分配的内存量的上限,并且可能会产生不利影响。


问题答案:

禁用显式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具有类似的功能。



 类似资料:
  • 问题内容: 在编写用于OpenGL库的Matrix类时,我遇到了一个问题,即使用Java数组还是使用Buffer策略存储数据(JOGL为Matrix操作提供直接缓冲区复制)。为了对此进行分析,我编写了一个小型性能测试程序,该程序比较了Arrays vs Buffers和Direct Buffers上循环和批量操作的相对速度。 我想在这里与您分享我的结果(因为我发现它们很有趣)。请随时发表评论和/或

  • 主要内容:1 Buffer的基本使用,2 Buffer的容量、位置、限制,3 Buffer的类型,4 Buffer的分配,5 将数据写入Buffer,6 从Buffer读取数据与NIO通道进行交互时,将使用Java NIO缓冲区。如您所知,数据从通道读取到缓冲区,然后从缓冲区写入通道。 缓冲区本质上是一个内存块,您可以在其中写入数据,然后可以在以后再次读取。该内存块包装在NIO Buffer对象中,该对象提供了一组方法,可以更轻松地使用该内存块。 1 Buffer的基本使用 使用Buffer来读

  • 问题内容: 由于它不在jvm heap&gc中,何时发布?还是一直保留到流程终止? 但是所有答案都是模糊的,没有一个明确的答案,是否有明确的答案?至少适用于 64位Linux 上的 Java 8 。 __ 问题答案: 不使用旧的Java终结器。相反,它使用内部API。它创建一个新线程并存储到每个创建的线程中(除了重复和切片指的是主缓冲区)。当变成 幻影可到达的 (也就是说,不再存在对字节缓冲区的强

  • 问题内容: 我有以下代码,旨在读取目录并将其压缩到tar.gz归档文件中。当我将代码部署到服务器上并使用一批文件对其进行测试时,它可以在前几个测试批处理中使用,但是在第4批或第5批处理之后,它将始终如一地为我提供java.lang.OutOfMemoryError:即使直接缓冲内存文件批处理大小保持不变,并且堆空间看起来不错。这是代码: } 这是一个例外: 我认为有一个缓冲区内存泄漏,因为它在前4

  • 问题内容: 有天赋的人能以简单明了的方式解释复杂的事情吗?为了在使用Java NIO进行网络I / O时应该使用直接ByteBuffer而不是常规ByteBuffer来获得最佳性能? 例如:我应该读入堆缓冲区并从那里解析它,做很多get()(逐字节),还是应该读入直接缓冲区并从直接缓冲区进行解析? 问题答案: 为了在使用Java NIO进行网络I / O时应该使用直接ByteBuffer而不是常规

  • 本文向大家介绍详细了解JAVA NIO之Buffer(缓冲区),包括了详细了解JAVA NIO之Buffer(缓冲区)的使用技巧和注意事项,需要的朋友参考一下 当我们需要与 NIO Channel 进行交互时, 我们就需要使用到 NIO Buffer, 即数据从 Buffer读取到 Channel 中, 并且从 Channel 中写入到 Buffer 中。缓冲区本质上是一块可以写入数据,然后可以从