有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java内存泄漏使用复制的列表将lambda提交到线程

我有一些简单的代码,它在一个专用线程中轮询消息,在一个列表中对消息进行批处理,然后将所述列表传递给另一个线程,以便执行一些涉及阻塞的操作。下面是一个简化的粗略近似值:

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(); 
    }
  }
}

因此,有两个线程,一个在使用消息,另一个在做事情。问题是,如果再过几天,这些线程就会停止运行(不过spring不会死机,我使用spring boot)

长话短说,我怀疑内存泄漏会杀死我的MessageProcessor,当我分析堆转储等时,如果有人能指出我在这段代码中可能缺少的任何东西,这将非常有帮助。特别是:

  • 我认为Operation没有被收集,是否clear()有效?我使用了一个Guava ImmutableList副本,但没有发布它,但是我假设它会被收集,因为doSomethingBlockingWith()在做了任何事情之后都会超出范围
  • 我真正的executor服务也是作为singleThreadExecutor,所以我可能会让submit()做更多它能处理的工作(批处理的速度可能比处理的速度快),这就是填充堆的原因

我使用了jvisualvm并分析了一点,启用了详细的垃圾收集器,使用了jmap之类的东西,但是所有的信息对我来说似乎都很神秘。到目前为止,我的堆似乎总是充满了字符串、长字符串和似乎由Operation持有的东西,但我不知道。谢谢你的帮助


共 (0) 个答案