Java:多线程邮件应用程序泄漏内存

Java:多线程邮件应用程序泄漏内存,java,multithreading,memory-leaks,Java,Multithreading,Memory Leaks,我有一个自己编写的Java应用程序——一个小型邮件监视器。它与一个MySQL数据库一起工作,该数据库有一个表,该表在其他地方定期填充。当记录出现在表中时,它查看表并发送邮件 我的问题是,应用程序泄漏内存。我很确定它没有,因为我使用的所有东西的范围似乎都消失了,使所有使用的对象都可以被垃圾回收。但是过了一段时间(取决于-Xmx I pass),应用程序会因OutOfHeapSpace错误而停止 我无法发布整个代码,因为它不再是我的,但我尝试使用伪代码重新创建它 Main: Startup

我有一个自己编写的Java应用程序——一个小型邮件监视器。它与一个MySQL数据库一起工作,该数据库有一个表,该表在其他地方定期填充。当记录出现在表中时,它查看表并发送邮件

我的问题是,应用程序泄漏内存。我很确定它没有,因为我使用的所有东西的范围似乎都消失了,使所有使用的对象都可以被垃圾回收。但是过了一段时间(取决于-Xmx I pass),应用程序会因OutOfHeapSpace错误而停止

我无法发布整个代码,因为它不再是我的,但我尝试使用伪代码重新创建它

Main:
  Startup
  Create .lock file (FileChannel)
  Instantiate Main Class

Constructor Main:
  Class.ForName for the MySQL driver
  Read properties file (settings)
  Create connection object (MySQL)
  Fetch unsent mail ids (ArrayList)
  while(true)
    while have more mail ids
      new Thread(Top Mail ID, MySQL Connection object, Sleep Time, Blacklist);
    end while
    if have no more mail ids in ArrayList:
      sleep for a number of seconds (usually 300)
    end if
  end while

Constructor Thread:
  Prepare Statement
  New Thread(this).start();
  Sleep

Thread run():
  Select Record by passed Mail ID
  Extract everything (Sender, Receiver, Subject etc.)
  Check Blacklist, return if matched
  Extract Attachments as blobs
到目前为止,我所尝试的:

jvisualvm向我展示了内存是如何随时间变化的。我看到的是堆中的一条锯齿线:分配和收集内存是有规律的,但是,在收集之后,分配的内存总是比上次收集之后多一点。线程的数量似乎很好,它总是下降到标准数量

jvisualvm中的信息量对我来说太多了。这里列出了一些我无法识别的线程,我创建的线程没有列为我的类,因此很难确定什么是“我的”代码

有人能在我的伪代码中识别出多线程的常见错误吗?有人能推荐一些工具让我更容易地确定我的漏洞吗

多谢各位

编辑1:通过传递给所有线程的连接对象进行的数据访问在自身上是同步的

编辑2:我检查了无法读取的邮件数量(因为这些邮件留在数据库中),大约有10封


编辑3:我找到了Eclipse内存分析器,安装了它,它暗示了这个问题。似乎在保留一个连接对象的同时使用PreparedStatements会保留一个HashMap,其中包含在该连接上运行的所有PreparedStatements,从而将所有选定的数据添加到该连接中。我依赖于准备好的报表超出范围并被收集。如果这能解决问题,我将重写并尝试。

从您的伪代码来看,似乎您正在为要发送的每封电子邮件创建一个线程,这似乎效率不高。我知道您提到线程数是“正常”的,但代码似乎表明不是这样。您是否可以尝试改用线程池,这样您的线程工作者数量有限,并通过某种作业队列将工作传递给他们

您知道是否有一些错误会导致线程无法完成或使其“挂起”吗?这可能是内存泄漏,因此请查看错误处理代码


在过去,我使用了
jprofiler
,并取得了一些成功,也许这是一个有用的选择。

如果有人对此感兴趣,我修复了内存问题

应用程序实际上没有泄漏内存。当我传递相同的连接对象时,它似乎将针对它运行的每个准备好的语句的结果保存在一个大的hashmap中。因此,内存使用率不断上升。我通过使用jvisualvm创建并加载到Eclipse内存分析器中的堆转储发现了这一点


我重写应用程序以使用线程池(缓存),为每个线程打开专用连接,并在每个线程结束时关闭连接。

在这种情况下,我至少会尝试一次FindBugs。我不知道该工具。现在安装。非常感谢。