1

私はかなり長い間AppleのEOFフレームワークを使用してきた問題と戦ってきました。EOEnterpriseObjectが作成されるか、DBから編集コンテキストに取り込まれると、関連するエンタープライズオブジェクト、編集コンテキスト、およびオブジェクトストアが破棄された後でも、EOFはオブジェクトが消費するメモリを解放しない場合があります。削除されました。ほとんどのオブジェクトはEOFによって適切に処理されるようですが、アプリが再起動されるまでEOFがオブジェクトによって使用されるメモリを一貫して保持する2つのオブジェクトがあります。これらのEOは両方とも非常に大きい可能性があります(ファイルの添付ファイルを保持するために使用されるNSDataオブジェクトが含まれています)。

JProfilerを使用して、問題のEOへの参照がEODatabase._snapshots配列によって保持されていることがわかりました。

他の誰かがEOFやプロジェクトWonderで同様の問題を抱えているのではないかと思っていました。私は2つの異なるシナリオで問題を一貫して見ているので、それがある程度一般的であり、したがって解決策があることを望んでいます。

最新のWebObjectsライブラリ(5.4.3)と最新のWonderライブラリを使用しています。

以下は私の正確なコードではありませんが、それでもメモリリークが発生する可能性のある最小の例です。

public WOActionResults createEmailHistoryEntry() throws MessagingException, IOException {
    File emailFile = new File("Email_with_large_attachment.eml");
    javax.mail.Message message = EmailUtils.convertEmlToMessage( emailFile );

    EOObjectStore osc = new ERXObjectStoreCoordinator(true);
    EOEditingContext ec = ERXEC.newEditingContext(osc);
    ec.lock();
    try {
        EmailHistoryEntry historyEntry = (EmailHistoryEntry) EOUtilities.createAndInsertInstance( ec, EmailHistoryEntry.class.getSimpleName() );
        EmailDataObject emailData = (EmailDataObject) EOUtilities.createAndInsertInstance( ec, EmailDataObject.class.getSimpleName() );
        emailData.setEmailHistoryEntry( historyEntry );

        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        message.writeTo( byteStream );
        NSData rawEmail = new NSData( byteStream.toByteArray() );
        emailData.setRawEmail( rawEmail );

        ec.saveChanges();
    }
    finally {
        ec.unlock();
        ec.dispose();
        osc.dispose();
    }
    return null;
}

私はそこで何か変わったことをしているのかわかりません。複数回実行すると、メモリ消費量は毎回約140MB増加し、最終的にOutOfMemoryエラーが発生します。

2012-12-26編集

私はこれについてもう少し調査しました。問題は、EOFライブラリではなく、ProjectWonderライブラリにあるようです。「問題」は、Wonder libではなく、私や私の理解である可能性が高いことを理解しています。:)

私は、これまでに見た問題を複製するテストアプリを作成し、それをgithubに投稿しました:https ://github.com/t-evans/memory-leak-test.git 。

テストアプリは、ほとんどの場合、新しいWonderアプリケーションを追加したときにEclipseが作成するデフォルトのアプリです。変更点は、Application.javaに1行追加され、Main.javaにほとんどのコードが追加され、もちろんモデルファイルが追加されたことです。現在、「memleaktest」という名前のpostgresデータベースに接続するように構成されています。

私のアプリの実行構成には、「-Xmx5m-Xmx50m」という2つのVM引数しかありません。アプリを起動して[オブジェクトの作成]リンクを約5回クリックすると、OutOfMemoryエラーが発生します。jConsoleを使用してメモリを監視すると、メモリ消費量が毎回約5MB増加し、アプリがそれらの5MBを手放すことはありません。

これまでの私の調査結果は、ERXObjectStoreCoordinatorSynchronizerが原因であることを示しています。テストアプリでは、Application.javaが同期をオンにします。Main.javaのコンストラクターは、ダミークエリを実行するだけで、最終的にMain._oscがERXObjectStoreCoordinatorSynchronizer.addObjectStore()に渡されます(シンクロナイザーは、何かを同期するために複数のOSCを必要とします)。Main.createDataStore()は、OSCとECを作成し、DataStoreオブジェクトをDBに追加してから、OSCとECを削除します。

新しいオブジェクト、OSC、およびECが削除され、破棄され、スコープから外れると、シンクロナイザーが実行され、新しく作成された(ただし現在は廃止された)オブジェクトが他のOSCに追加され、最終的に新しいオブジェクトが再度追加されます。 EODatabase._snapshots配列に追加され、他のOSCが破棄されるまで残ります。

新しいEOがその後他のOSCと同期され、ECとOSCが機能しなくなり、範囲外になるのは奇妙に思えます。シンクロナイザーは、EOがスコープ外であるという事実を同期して、他のすべてのOSCから削除する(または、そもそも他のOSCを追加しない)べきではありませんか?

を呼び出すことで同期をオフにできることを知っています

ERXObjectStoreCoordinatorSynchronizer.synchronizer().setDefaultSettings(
    new SynchronizerSettings(false, false, false, false));

これで問題は回避されますが、シンクロナイザーのデフォルト設定ではすべてがオンになっているため、かなり大きなリークが発生します。

これはバグですか、それとも私は何か間違ったことをしていますか?他の人がこれに遭遇していないように見える理由は私は混乱しています。または、おそらく彼らはそれに遭遇していますが、大きなEOを使用していないためにメモリリークに気づいていません(?)

4

3 に答える 3

1

私が見つけた最善の解決策は、ERXObjectStoreCoordinatorSynchronizer を回避するか (シンクロナイザーを使用するため、ERXObjectStoreCoordinatorPool も回避する必要があることを意味します)、次のようにシンクロナイザーを無効にすることです。

ERXObjectStoreCoordinatorSynchronizer.synchronizer().setDefaultSettings(新しい SynchronizerSettings(false, false, false, false));

または、InsertSnapshotProcessor を無効にするだけで済む可能性があります。

ERXObjectStoreCoordinatorSynchronizer.synchronizer().setDefaultSettings(new SynchronizerSettings(false, true , true , true ));

それがメモリリークが発生しているように見える場所です(他のものも問題を引き起こす可能性がありますが、私は特にそれを見たことはありません).

Project Wonder メール グループに投稿した後、上記よりも優れた解決策を持っている人は誰もいないようです。

于 2012-12-31T19:00:47.470 に答える
0

コードのすべての部分を検証し、プロファイリングしていただければ幸いです。しかし、それでも問題はあなたのコードだけにあると感じています。

次のことをもう一度確認する価値があります: EO、EC、NSData オブジェクト、コンポーネントへの参照と、巨大なオブジェクトのどこかで、さらに重要なことに、EC が GC 処理されていないかどうかを確認してください。

問題が解決しない場合は、この問題のデバッグに役立つ情報がさらに必要になる場合があります。

于 2012-04-28T02:40:20.477 に答える