【发布时间】:2012-06-11 09:06:14
【问题描述】:
我有一个自己编写的 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 超出范围并被收集。我会重写并尝试是否可以解决问题。
【问题讨论】:
-
在这种情况下,我至少会尝试一次 FindBugs。
-
我不知道那个工具。现在安装。谢谢。
标签: java multithreading memory-leaks