更新到wildfly 18后直接缓冲内存OutOfMemoryError

Lon*_*zak 5 java out-of-memory wildfly undertow java-11

将环境从 更新到 后,Wildfly 13我们Wildfly 18.0.1经历了

A channel event listener threw an exception: java.lang.OutOfMemoryError: Direct buffer memory
at java.base/java.nio.Bits.reserveMemory(Bits.java:175)
at java.base/java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:118)
at java.base/java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:317)
at org.jboss.xnio@3.7.3.Final//org.xnio.BufferAllocator$2.allocate(BufferAllocator.java:57)
at org.jboss.xnio@3.7.3.Final//org.xnio.BufferAllocator$2.allocate(BufferAllocator.java:55)
at org.jboss.xnio@3.7.3.Final//org.xnio.ByteBufferSlicePool.allocateSlices(ByteBufferSlicePool.java:162)
at org.jboss.xnio@3.7.3.Final//org.xnio.ByteBufferSlicePool.allocate(ByteBufferSlicePool.java:149)
at io.undertow.core@2.0.27.Final//io.undertow.server.XnioByteBufferPool.allocate(XnioByteBufferPool.java:53)
at io.undertow.core@2.0.27.Final//io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:147)
at io.undertow.core@2.0.27.Final//io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:136)
at io.undertow.core@2.0.27.Final//io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:59)
at org.jboss.xnio@3.7.3.Final//org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
at org.jboss.xnio@3.7.3.Final//org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66)
at org.jboss.xnio.nio@3.7.3.Final//org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89)
at org.jboss.xnio.nio@3.7.3.Final//org.xnio.nio.WorkerThread.run(WorkerThread.java:591)
Run Code Online (Sandbox Code Playgroud)

应用程序方面没有任何改变。我查看了缓冲池,似乎有些资源没有释放。我触发了几次手动 GC,但几乎什么也没发生。(正常运行时间2小时)

缓冲池稳步增长

之前在旧配置中它看起来像这样(正常运行时间> 250小时):

正确释放的缓冲池

现在我做了很多研究,我能找到的最接近的就是这篇关于 SO 的文章。然而,这是与 websockets 结合使用的,但没有使用websockets。我读了几篇(好)文章1、2、3、4、5、6 观看了有关主题视频我尝试了以下方法,但没有任何效果:

  1. OutOfMemoryError 发生在 5GB 处,因为堆是 5GB => 我将 MaxDirectMemorySize 减少到 512m,然后是 64m,但 OOM 发生得更快
  2. 我设置-Djdk.nio.maxCachedBufferSize=262144
  3. 我检查了 IO 工作线程的数量:96(6cpus*16),这似乎是合理的。系统通常具有短暂生命周期的线程(最大池大小为 13)。所以我猜这不可能是工人的数量
  4. 我切换回 ParallelGC,因为这是 Java8 中的默认设置。现在,当执行手动 GC 时,至少会释放 10MB。对于 GC1,什么也没有发生。但两个 GC 仍然无法清理。
  5. <websockets>为了确定起见,我从 Wildfly 配置中删除了
  6. 我试图在本地模拟它,但失败了。
  7. 我使用 eclipseMAT 和 JXRay 分析了堆,但它只指向一些内部的 Wildfly 类。JXRay 显示 1544 个被引用为 DirectByteBuffers 的对象
  8. 我将 Java 恢复到版本 8,系统仍然显示相同的行为,因此 Wildfly 是最有可能的嫌疑。

在 eclipseMAT 中也可以找到这 1544 个对象。它们的尺寸都相同。 eclipseMAT 显示 DirectByteBuffer 引用

唯一有效的是完全停用 Wildfly 中的字节缓冲区。

/subsystem=io/buffer-pool=default:write-attribute(name=direct-buffers,value=false)
Run Code Online (Sandbox Code Playgroud)

但是从我读到的内容来看,这有性能缺陷吗?

那么有人知道问题是什么吗?有关其他设置/调整的任何提示吗?或者是否存在与此相关的已知 Wildfly 或 JVM 错误?

更新 1:关于 IO 线程 - 也许这个概念对我来说并不是 100% 清楚。因为有它的ioThreads价值 在此输入图像描述 还有线程和线程池。 在此输入图像描述

根据定义,人们可能会认为每个工作线程ioThreads创建的数量(在我的例子中为 12)?但在我的情况下,线程/工作线程的数量似乎仍然很低......

更新 2:我降级了 java,但它仍然显示相同的行为。因此我怀疑野蝇是造成这个问题的原因。

Lon*_*zak 1

经过大量分析、分析等后,我得出以下结论:

  • OOM的原因是18.0.1版本中的wildfly引起的。19.1.0中也存在(没有测试20或21)
  • -XX:MaxDirectMemorySize当将值设置为 512m 或更低时,我能够相当快地触发 OOM 。我认为很多人都没有遇到这个问题,因为默认情况下该值等于 Xmx 值,该值可能非常大。使用我们应用程序的ReST API时出现问题
  • 正如 Evgeny 所指出的那样,XNIO 是一个很有潜力的候选者,因为在分析时它的范围缩小到(或附近)该区域......
  • 我没有时间进一步调查,所以我尝试了 Wildfly 22,它正在工作。该版本使用最新的xnio包(3.8.4)
  • WF 22 中的 DirectMemory 仍然很低。大约为 10mb。人们可以看到计数的上升和下降,而以前的情况并非如此

所以最终的修复是更新到wildfly版本22.0.1(或更高版本)