【发布时间】:2019-06-06 04:16:25
【问题描述】:
我不是 ActiveMQ 专家,但是我尝试在 Internet 上搜索了很多类似的问题,但我仍然很困惑。我有以下问题。
在 Tomcat 8.x、Java 8、Spring Framework 4.3.18 中运行 Web 应用程序。
我的 Web 应用程序使用 org.apache.activemq:activemq-spring:5.11.0 依赖项使用 ActiveMQ 发送和接收消息。
我正在以这种方式设置 ActiveMQ 连接工厂:
<amq:connectionFactory id="amqJmsFactory" brokerURL="${jms.broker.url}" />
<bean id="jmsConnectionFactory"
class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
<property name="connectionFactory" ref="amqJmsFactory" />
<property name="maxConnections" value="2" />
<property name="idleTimeout" value="60000" />
<property name="timeBetweenExpirationCheckMillis" value="600000" />
<property name="maximumActiveSessionPerConnection" value="10" />
</bean>
最后一个属性 (maximumActiveSessionPerConnection) 已设置为尝试解决以下问题(默认值似乎是 500,恕我直言,这是相当高的),但我不确定它是否真的有帮助,因为我仍然出现 OutOfMemory 错误。
这个连接工厂被一个监听容器工厂引用:
<jms:listener-container factory-id="activationJmsListenerContainerFactory"
container-type="default" connection-factory="jmsConnectionFactory"
concurrency="1" transaction-manager="centralTransactionManager">
</jms:listener-container>
通过一个 Spring Integration 4.3.17 入站适配器:
<int-jms:message-driven-channel-adapter id="invoiceEventJmsInboundChannelAdapter"
channel="incomingInvoiceEventJmsChannel"
connection-factory="jmsConnectionFactory"
destination-name="incomingEvent"
max-concurrent-consumers="2"
transaction-manager="customerTransactionManager"
error-channel="unexpectedErrorChannel" />
并通过两个出站适配器:
<int-jms:outbound-channel-adapter id="invoiceEventJmsOutboundChannelAdapter"
channel="outgoingInvoiceEventJmsChannel" destination-name="outgoingEvent"
connection-factory="jmsConnectionFactory" explicit-qos-enabled="true" delivery-persistent="true"
session-transacted="true" />
<int-jms:outbound-channel-adapter
id="passwordResetTokenSubmitterJmsOutboundChannelAdapter"
channel="passwordResetTokenSubmitterJmsChannel"
destination-name="passwordReset"
connection-factory="jmsConnectionFactory" explicit-qos-enabled="true"
delivery-persistent="false" session-transacted="false" />
一切运行良好,但我观察到 ActiveMQ 作为消息生产者(用于invoiceEventJmsOutboundChannelAdapter 适配器)在内存中累积了大量对象,这导致我的应用程序出现 OutOfMemory 错误。我的消息可能有几 KB 长,因为它们的有效负载是 XML 文件,但我不希望长时间持有这么多内存。
这是我对最近的 OutOfMemory 错误(使用 Eclipse MAT 进行调查)产生的堆转储的发现。发现了两个泄漏嫌疑人,都指向ConnectionStateTracker。
这是两个累加器之一:
Class Name | Shallow Heap | Retained Heap
-------------------------------------------------------------------------------------------------------------------------------------------
java.util.concurrent.ConcurrentHashMap$HashEntry[4] @ 0xe295da78 | 32 | 58.160.312
'- table java.util.concurrent.ConcurrentHashMap$Segment @ 0xe295da30 | 40 | 58.160.384
'- [15] java.util.concurrent.ConcurrentHashMap$Segment[16] @ 0xe295d9e0 | 80 | 68.573.384
'- segments java.util.concurrent.ConcurrentHashMap @ 0xe295d9b0 | 48 | 68.573.432
'- sessions org.apache.activemq.state.ConnectionState @ 0xe295d7e0 | 40 | 68.575.312
'- value java.util.concurrent.ConcurrentHashMap$HashEntry @ 0xe295d728 | 32 | 68.575.344
'- [1] java.util.concurrent.ConcurrentHashMap$HashEntry[2] @ 0xe295d710 | 24 | 68.575.368
'- table java.util.concurrent.ConcurrentHashMap$Segment @ 0xe295d6c8 | 40 | 68.575.440
'- [12] java.util.concurrent.ConcurrentHashMap$Segment[16] @ 0xe295d678 | 80 | 68.575.616
'- segments java.util.concurrent.ConcurrentHashMap @ 0xe295d648 | 48 | 68.575.664
'- connectionStates org.apache.activemq.state.ConnectionStateTracker @ 0xe295d620| 40 | 68.575.808
-------------------------------------------------------------------------------------------------------------------------------------------
如您所见,ConnectionStateTracker 的实例保留了大约 70 MB 的堆空间。 ConnectionStateTracker 有两个实例(我猜每个出站适配器一个),它们总共保留了大约 120 MB 的堆。他们在ConnectionState 的两个实例中累积它,而这两个实例又具有一个“会话”映射,其中包含累积总共 10 个SessionState 实例,而这些实例又具有ConcurrentHashMap 的生产者,累积总数为 1,258 @ 987654335@ 个实例。它们在 transactionState 字段中保留了这 120 MB 的堆,该字段的类型为 TransactionState,而 commands ArrayList 似乎保留了我要发送的全部消息。
我的问题是:为什么 ActiveMQ 将已经发出的消息保存在内存中?将所有这些消息保存在内存中也存在一些安全问题。
【问题讨论】:
标签: java spring spring-integration activemq