3

Javamail を使用するサーバーを実行しています。IMAP の IDLE を備えたカウント リスナーがあり、新しいメールが届いたときに特定のコードが実行されます。新しいメッセージのリストは、パラメーターとしてリスナーに渡されます。私はそれから情報を読み、それで終わります。私のサーバーが大量のメモリをリークすることを除けば、すべて問題ありません!! ヒープ ダンプを行ったところ、[Lcom.sun.mail.imap.IMAPMessage クラスが大量のメモリを使用していることがわかりました。IMAPMessage の配列がオブジェクト com.sun.mail.imap.MessageCache によって参照されているようです。

キャッシングは行われていますか?初めてメッセージを受信する場合を除いて、これらのメッセージに再度アクセスする必要はありません。キャッシュを強制的にクリアするにはどうすればよいですか? javamail の漏洩を防ぐにはどうすればよいですか?

4

3 に答える 3

1

Javamail フォーラムでこのリファレンスを見つけました Javamail にメッセージ キャッシュを強制的にクリアする方法は?

そして、少し掘り下げました。「キャッシュ」を削除または縮小する方法は見つかりませんでしたが、そのキャッシュの最大の部分はメッセージのヘッダーであることがわかりました。IMAPMessage 内にはヘッダーのコピーが 2 つあります。1 つは IMAPMessage 内にあり、もう 1 つは MIMEMessage 内に入力されます。IMAPMessage の情報を消去するためのアクセス権しか与えられないため、この情報を消去したい場合に問題が発生します。MIMEMessage のヘッダーをクリアできません。さらに、それらは削除できません。InternetHeaders.remove(String) のコードは次のとおりです。

/**
 * Remove all header entries that match the given name
 * @param   name    header name
 */
public void removeHeader(String name) { 
for (int i = 0; i < headers.size(); i++) {
    InternetHeader h = (InternetHeader)headers.get(i);
    if (name.equalsIgnoreCase(h.getName())) {
    h.line = null;
    //headers.remove(i);
    //i--;    // have to look at i again
    }
}
}

とにかく、これらの値をすべて入力して無効にすることで、MessageCache によって保存されるメモリを劇的に減らすことができました。

Field headerField = MimeMessage.class.getDeclaredField("headers");
headerField.setAccessible(true);
InternetHeaders headers = (InternetHeaders) headerField.get(imapMessage);
if (headers != null) {
   Enumeration<?> allHeaders = headers.getAllHeaders();
   ArrayList<String> headerNames = new ArrayList<String>();
   while (allHeaders.hasMoreElements()) {
       Header header = (Header) allHeaders.nextElement();
       headerNames.add(header.getName());
   }
   for (String headerName : headerNames) {
       headers.setHeader(headerName, null);
   }
}

それほどきれいではありませんが、1 つのフォルダーのメモリ使用量が 40MB から 20MB に減少します。これを行う他の方法があるかどうかを確認します。理想的には、オーバーライドされた独自の IMAPMessage クラスを作成すると思いますが、それを組み込むのは非常に難しいようです。

于 2012-02-08T22:50:08.140 に答える
0

Sun の実装が気に入らない場合は、別の Java Mail 実装を試すことができます。GNU クラスパスに 1 つある ( http://www.gnu.org/software/classpathx/javamail/javamail.htmlで)

于 2009-11-21T21:12:12.687 に答える
0

docsによると、ブール値を渡して、削除されたメッセージを消去する必要があることを示します。

message.setFlag(Flags.Flag.DELETED, true);
folder.close(aBoolean);
store.close();
于 2009-11-23T12:00:56.817 に答える