私は自分で書いた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を見つけてインストールしたところ、問題が示唆されました。1つの接続オブジェクトを保持しながらPreparedStatementsを使用すると、その内部のこの接続で実行されるすべてのPreparedStatementsのHashMapが保持されるため、選択されたすべてのデータが追加されるようです。私はPreparedStatementが範囲外になり、収集されることに依存していました。これで問題が解決するかどうか、書き直して試してみます。