【发布时间】:2014-08-06 16:18:32
【问题描述】:
我们的 ActiveMQ 消费进程耗尽内存并死亡。
我们有一个 ActiveMQ 主题,其中有一个发送者和两个接收者。从表面上看,一切正常——消息被两个接收者发送和接收,但最终我们耗尽了所有内存。堆转储显示 LinkedList$Node、AtomicReference、ActiveMQObjectMessage、MessageId 和 MessageDispatch 各有 136.2 万个实例。同时,客户端消息队列始终是空的或几乎是空的。我认为 1.362M 可能在跟踪未确认消息等待确认的列表中。该主题被指定为设置了 AUTO_ACKNOWLEDGE,因此我们正在尝试确认,但可能会失败。 (jmsSession = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);)
堆转储显示似乎与客户端传入消息缓冲相关的垃圾数量适中(几千)。这似乎与我们设置用于发送和使用类似对象的玩具程序中累积的这些对象的数量一致。它们积累了一段时间,然后被 GC 处理,并且在玩具或失败的程序中内存永远不会显着增长。
推测这五种对象类型与 ACKS 相关联是否正确,如果是这样,尽管显然已被两个消费者完全消费,但什么会导致对象保留在此结构上?有什么方法可以取消我们认为已经设置的 AUTO_ACKNOWLEDGE?顺便说一句,一个消费者是同步的,使用receive(),另一个是异步的,使用onMessage()。
一个可能具有误导性的症状是 ActiveMQ GUI 显示对象仅出队一次,尽管存在两个消费者。该玩具为每个入队显示了两个出队。但是,程序本身说它们被读取了预期的次数。
// creating the async consumer.
connAmq = createActiveMqConnection();
connAmq.start();
session = connAmq.createSession(true, Session.AUTO_ACKNOWLEDGE);
Destination topic = session.createTopic(appProperties.getActiveMqTopicQuotesName());
MessageConsumer consumer = session.createConsumer(topic);
consumer.setMessageListener(this);
public void onMessage(Message message) {
...
try {
if (message instanceof ObjectMessage) {
ObjectMessage msg = (ObjectMessage)message;
if (msg instanceof Foo) {
Foo quote = (Foo)msg.getObject();
...
}
}
}
...
}
// creating the sync consumer
jmsConnection = mActiveMQConnectionFactory.createTopicConnection();
jmsConnection.start();
jmsSession = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
jmsDestination = jmsSession.createTopic(name);
jmsMessageConsumer = jmsSession.createConsumer(jmsDestination);
//the code for consuming looks like this for the synchronous consumer
while(true)
ObjectMessage m = (ObjectMessage) jmsMessageConsumer.receive();
if (m != null)
Process(m.getObject());
}
【问题讨论】:
-
谢谢---但这是我的错字。失败的代码将交易值设置为假。我已经简化了,因为它是一个变量,而不是字面的“假”。看起来像:session = connAmq.createSession(false, Session.AUTO_ACKNOWLEDGE);
-
session = connAmq.createSession(false, Session.AUTO_ACKNOWLEDGE);
标签: java out-of-memory activemq