java.lang.OutOfMemory
常见问题解答 > 错误 > 异常 > java.lang.OutOfMemory
好的,这是可以处理的。可以配置几乎所有 ActiveMQ Classic 的内存使用情况。首先要确定的是系统中哪个部分内存不足。是 JVM、代理、消费者还是生产者?
此条目适用于 ActiveMQ Classic 5.1.x 及更高版本。
内存
JVM 内存
尝试使用 bin/activemq
在独立 JVM 中运行代理。请注意脚本传递给 Java 可执行文件的默认 JVM 堆大小选项(确切的选项可能取决于您使用的 JVM,以下示例适用于 Sun JVM)。
- -Xmx:如果您的操作系统有更多可用内存,请考虑增加代理 JVM 可用的总堆内存。请注意,JVM 将需要比 -Xmx 值更多的内存。线程堆栈和 JMVs 内部类将占用额外的内存。
- -Xss:如果您在代理 JVM 中有 大量线程,请考虑使用 -Xss 选项减少每个线程的默认 JVM 堆栈大小。
如果您运行的是嵌入式代理或第三方容器,请确保托管 JVM 具有适合最大堆大小和堆栈大小的值。
代理内存
代理允许使用的内存量并非由分配给 JVM 的内存量决定。尽管代理受 JVM 给予的内存量限制,但代理会独立管理其内存。也就是说,代理不会简单地使用掉 JVM 中的所有内存,然后以 OutOfMemory 异常死亡。这就是您需要了解 systemUsage 内存限制和每个目标的内存限制的地方。
ActiveMQ Classic 中的内存以分层方式工作,从 JVM -> 代理 -> 代理功能。例如,放置的总目标内存限制不能超过代理的内存限制。
消费者
除了消息大小之外,预取限制 是消费者 内存不足 的主要原因。降低预取值将减少消费者内存中排队/存储的消息数量。
生产者
除非消息大小超过资源限制,否则生产者不应出现内存不足。生产者可能会注意到代理执行内存限制的影响,表现为 阻塞。
其他
将消息分页到磁盘
只有当消息存储在内存中时,才能快速分发消息。当消费者速度慢或不存在时,内存会很快耗尽。
代理(使用 消息游标)将在到达目标的默认内存使用阈值时将非持久消息分页到磁盘。此阈值是通过以下内容指定给代理的
可以在 activemq.xml 中使用 每个目标策略 指定更具体的每个目标 memoryUsage 限制。[消息游标](message-cursors) 参考中提供了有关
线程数量
默认情况下,ActiveMQ Classic 为每个目标使用一个专用线程。如果目标数量很多,将有大量线程及其关联的内存资源使用情况。可以通过使用系统属性将 ActiveMQ Classic 配置为使用线程池:-Dorg.apache.activemq.UseDedicatedTaskRunner=false。这目前在 activemq 启动脚本中通过 ACTIVEMQ_OPTS 指定。使用线程池可以限制 ActiveMQ Classic 需要的线程数量,从而减少内存使用。
非常大的消息
当您的消息非常大,以至于您一次只能允许少量消息在内存中时,每个目标策略 maxPageSize 和 lazyDispatch 可以提供帮助。maxPageSize 控制分页到内存以进行分发的消息数量,而 lazyDispatch 使用当前消费者列表的预取容量来增加该值。对于预取值为 1、单个消费者和 lazyDispatch,一次只会将一条消息加载到内存中。
泄漏 JMS 资源
这对消费者或生产者来说是最明显的;反复获取 Session 或 MessageProducer 或 MessageConsumer 而不关闭它。对于 java.lang.OutOfMemory,验证(再次)所有未使用的 JMS 资源是否已释放是值得的。如果您的应用程序中有多个线程,请考虑使用 PooledConnectionFactory,因为它允许安全地在遵循以下模式的线程之间共享 JMS 资源
obtainJmsResource();
try
{
useJmsResource()
} finally {
releaseJmsResource();
}
如果您通过 Spring 支持 或使用 JMSTemplates 使用 ActiveMQ Classic,请确保您没有遇到任何 JmsTemplate 陷阱。可能还值得回顾一下 如何有效使用 JMS。