我有一个MDB,它使用来自队列的消息,然后调用无状态EJB来执行一些数据库操作。像这样:
public class TestMDB implements MessageListener
{
@EJB
private UpdateService updateSvc;
@Override
public void onMessage(Message message)
{
try
{
updateSvc.updateSystemStatuses();
}
catch(Exception e)
{
// log error
}
}
}
在上面的代码中,如果updateSystemStatuses()调用抛出RuntimeException,这似乎会导致内存泄漏。我通过引入updateSystemStatuses()来抛出RuntimeExceptions来加速这个过程,当这种情况发生时CPU使用率和内存使用量激增(在JVisualVM中观察到),直到我开始得到OutOfMemoryErrors。
如果我修改代码以将RuntimeExceptions抛出onMessage,资源泄漏似乎完全消失了:
public class TestMDB implements MessageListener
{
@EJB
private UpdateService updateSvc;
@Override
public void onMessage(Message message)
{
try
{
updateSvc.updateSystemStatuses();
}
catch(RuntimeException e)
{
//log error
throw e;
}
catch(Exception e)
{
//log error
}
}
}
我知道从EJB方法中抛出RuntimeException会导致事务回滚,我认为这与我所看到的有关,但除此之外,我不清楚这里发生了什么。资源是否泄漏了Glassfish错误?我是否正确处理MDB中的异常?
我使用Eclipselink和Oracle 11G在Java 1.6.0_35上运行Glassfish 3.1.2.2。
答案 0 :(得分:0)
我认为您正面临“毒药消息”的情况。您的MDB在队列中提取消息并尝试处理它。由于处理失败(抛出异常),消息将被放回队列中。然后又一次又一次地处理。这就是为什么你看到CPU通过屋顶。
使用Glassfish,您可以指定在忽略之前处理消息的次数(即,如果处理引发异常)。您可以在此博客上找到有用的信息:
http://weblogs.java.net/blog/felipegaucho/archive/2009/09/24/handling-poison-messages-glassfish