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

标签 java multithreading memory-leaks

我有一个自己编写的 Java 应用程序 - 一个小型邮件监视器。它与 MySQL 数据库配合使用,该数据库有一个定期在其他地方填充的表。它会查看表格并在表格中显示记录时发送邮件。

我的问题是,应用程序泄漏内存。我非常确定它没有,因为我使用的所有对象的范围似乎都消失了,使得所有使用的对象都可以垃圾收集。但过了一会儿(取决于我传递的 -Xmx),应用程序因 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 Memory Analyzer,安装了它,它暗示了问题。看起来,在保留一个连接对象的同时使用PreparedStatements 会保留在其中运行过该连接的所有PreparedStatements 的HashMap,因此将所有选定的数据添加到其中。我依赖于PreparedStatement 超出范围并被收集。我将重写并尝试是否可以解决问题。

最佳答案

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

您是否知道是否存在一些可能导致线程无法完成或让它们“挂起”的错误?这可能是内存泄漏,因此请检查您的错误处理代码。

过去我使用jprofiler并取得了一些成功,也许它会是一个有用的替代方案。

关于Java:多线程邮件应用程序泄漏内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10977116/

相关文章:

java - 使用 JNI 从 C 调用 java 代码时发生内存泄漏

java - 我想删除一个文件并将新文件重命名为旧文件

java - 媒体应用程序缓冲时间太长

java - wav 文件打开后无法删除,java

c - LIBUMEM 说没有内存泄漏,但 Solaris 上的 PRSTAT 显示泄漏?

java - 同步一组线程

java - 解析 URLConnection 中的所有数据后,打破异步任务中的 do while 循环

java - 将 Spock 与 Jenkins、Sonar 集成的最佳实践

java - close-group 问题 java RTFEditorKit

c++ - 多线程排挤其他进程