我有一些简单的代码,用于轮询专用线程中的消息,在列表中对它们进行批处理,然后将所述列表传递给不同的线程,以便执行涉及阻塞的操作。这是一个简化的粗略近似值:
class MessageProcessor extends MessagePoller implements Runnable {
private final ExecutorService batchHandlerExec = Executors.newSingleThreadExecutor();
private final List<Operation> operations = new ArrayList();
//just to indicate this is a thread started somewhere
public void run() { while(true) processMessage(); }
public void processMessage() {
Message msg = poll();
operations.add(Operation.buildFrom(msg));
if(operations.size() >= SOME_NUMBER) {
List<Operations> batch = ImmutableCopy.copyOf(operations);
batchHandlerExec.submit(() -> doSomethingBlockingWith(batch));
operations.clear();
}
}
}
所以有两个线程,一个消费消息,另一个消息。问题是,给定几天,这些线程将停止运行(虽然没有弹簧死亡,但我使用弹簧启动)
长话短说,我怀疑内存泄漏导致我的MessageProcessor死机,而我正在分析堆转储等等,如果有人能指出我在这段代码上可能遗漏的任何内容,那将非常有用。特别是:
Operation
未被收集,clear()
是否有效?我使用Guava ImmutableList副本而不释放它,但我认为它会被收集,因为doSomethingBlockingWith()
在做了它做的任何事情后都会超出范围submit()
(批处理可能比处理它们更快),那是什么填充堆?我已经使用 jvisualvm 并分析了一下,启用了详细的垃圾收集器,使用了jmap和东西,但所有信息对我来说似乎都很神秘。到目前为止,我的堆似乎总是充满了字符串,长篇和似乎由Operation
持有的东西,但我不知道。任何帮助表示赞赏