Spring Azure qPID JMS代码中的跟踪内存泄漏

问题描述 投票:1回答:1

我试图在我们非常小的和简单的Spring Boot应用程序中跟踪和识别导致内存泄漏的根本原因。

它使用以下内容:-Spring Boot 2.2.4-azure-servicebus-jms-spring-boot-starter 2.2.1-MSSQL

功能:该应用程序仅调度Azure ServiceBus队列并存储数据,并将数据发送到其他目标。这是一个小型应用程序,因此尽管我通过Xmx选项最多提供了256兆的内存,但它还是很容易以64兆的内存开始。重要说明是使用专用JmsTransactionManager(实际上是ChainedTransactionManager的内部TM)以及dbTM和附加出站JMS TM的专用JmsTransactionManager使用Spring默认事务处理模式调度队列。这两个JMS ConnectionFactory对象都创建为CachingConnectionFactory。

行为:

启动该应用程序后,看起来不错。没有流量,因此我在日志中可以看到它正在打开事务并在检查队列时关闭(jms:message-driven-channel-adapter)。

但是经过一段时间之后仍然没有流量,没有消息被消耗,通过JVVM监视的内存开始上升。

抛出错误:

--2020-04-24 11:17:01.443 - WARN 39892 ---   [er.container-10] o.s.j.l.DefaultMessageListenerContainer  : Setup of JMS message listener invoker failed for destination 'MY QUEUE NAME HERE' - trying to recover. Cause: Heuristic completion: outcome state is rolled back; nested exception is org.springframework.transaction.TransactionSystemException: Could not commit JMS transaction; nested exception is javax.jms.IllegalStateException: The Session was closed due to an unrecoverable error.

...几分钟后,它达到堆的最大值,从那一刻起,它由于打开JMS连接的线程中的OutOfMemory错误而失败。

--2020-04-24 11:20:04.564 - WARN 39892 ---   [windows.net:-1]] i.n.u.concurrent.AbstractEventExecutor   : A task raised an exception. Task: org.apache.qpid.jms.provider.amqp.AmqpProvider$$Lambda$871/0x000000080199f840@1ed8f2b9
-
java.lang.OutOfMemoryError: Java heap space
        at java.base/java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:61)
        at java.base/java.nio.ByteBuffer.allocate(ByteBuffer.java:348)
        at org.apache.qpid.proton.engine.impl.ByteBufferUtils.newWriteableBuffer(ByteBufferUtils.java:99)
        at org.apache.qpid.proton.engine.impl.TransportOutputAdaptor.init_buffers(TransportOutputAdaptor.java:108)
        at org.apache.qpid.proton.engine.impl.TransportOutputAdaptor.pending(TransportOutputAdaptor.java:56)
        at org.apache.qpid.proton.engine.impl.SaslImpl$SwitchingSaslTransportWrapper.pending(SaslImpl.java:842)
        at org.apache.qpid.proton.engine.impl.HandshakeSniffingTransportWrapper.pending(HandshakeSniffingTransportWrapper.java:138)
        at org.apache.qpid.proton.engine.impl.TransportImpl.pending(TransportImpl.java:1577)
        at org.apache.qpid.proton.engine.impl.TransportImpl.getOutputBuffer(TransportImpl.java:1526)
        at org.apache.qpid.jms.provider.amqp.AmqpProvider.pumpToProtonTransport(AmqpProvider.java:994)
        at org.apache.qpid.jms.provider.amqp.AmqpProvider.pumpToProtonTransport(AmqpProvider.java:985)
        at org.apache.qpid.jms.provider.amqp.AmqpProvider.lambda$close$3(AmqpProvider.java:351)
        at org.apache.qpid.jms.provider.amqp.AmqpProvider$$Lambda$871/0x000000080199f840.run(Unknown Source)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:510)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:518)
        at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at java.base/java.lang.Thread.run(Thread.java:835)

HeapDumps:

我在整个过程中拍摄了几个堆快照,并查看增加了什么。我可以看到可疑数量的ConcurrentHashMap / String / Byte []对象。

有任何线索/提示在此设置和库中有什么问题吗:Spring Boot,Azure JMS依赖项下使用的Apache qPid等?非常感谢。

enter image description here

更新#1我有明确的证据表明问题出在Spring或Azure服务总线启动程序库中-不是自动使用qPid客户端。 我想说的是,库是bug而不是Spring,只是我的猜测。失败的设置是这样的:

  1. 有两个JMS目标和一个DB,每个都有其事务管理器
  2. 在三个TM上方都有ChainedTransactionManager包装。
  3. 通过jms:message-driven-channel-adapter连接到Azure ServiceBus队列并在该组件上设置事务管理器的Spring集成应用程序(在第2点中创建)
  4. 启动应用程序,不需要队列上的任何流量,在10分钟后,该应用程序将因OutOfMemoryError而崩溃...在这10分钟内,我观察到调试级别的日志,唯一正在发生的事情是使用来打开和关闭事务ChainedTransactionManager ...也如注释中所述,另一个重要条件是第三个JMS TransactionManager ...具有2个TM且稳定,具有3个TM将会崩溃...
spring-boot spring-integration azureservicebus spring-jms qpid
1个回答
0
投票

其他研究和采取的步骤确定了Spring CachingConnectionFactory类的最可能根本原因。一旦删除了该内容并仅使用本机类型,问题就消失了,内存消耗状况也变得非常不同且健康。

我不得不说我使用标准构造函数创建了CachingConnectionFactory,并且没有进一步配置行为。但是,根据我的经验,这些Spring默认值显然会导致内存泄漏。

过去我有ActiveMq的内存泄漏,必须使用CachingConnectionFactory解决,现在使用CachingConnectionFactory时我与Azure ServiceBus发生内存泄漏。.奇怪:)在两种情况下,我都认为导致错误,因为无论是否涉及缓存,内存管理都应该正确。

将此标记为我的答案。

经过测试的情况:使用自己的TM和两个JMS connectionFactories都类型CachedConnectionFactory接收和发送消息时,会发生问题。最后,我测试了该应用程序。具有CachedConnectionFactory类型的入站连接工厂,而出站只是本机类型...也没有内存泄漏。

© www.soinside.com 2019 - 2024. All rights reserved.