2

コンストラクターが他のオブジェクト(Object2)のインスタンスを作成し、それらをArrayListに格納するオブジェクト(Object1)のインスタンスがあります。Object2には(他の静的変数の中でも)静的instancecount変数があり、Object2のインスタンスはこのinstancecountに依存します。テストプログラムでは、反復ごとにObject1のインスタンスが作成されるforループを実行し、Object1のインスタンスへの参照にnull値が再割り当てされます。私のテストプログラムは次のようになります。

    for (...) {
        Object1 obj = new Object1(...); //which creates several Object2's
        obj.myMethod();
        obj = null;
    }

問題は、Object2のインスタンスが各ループ反復の終了時にガベージコレクションを取得していないため、Object2の静的instancecount変数は、反復ごとに(メモリ使用量とともに)大きくなります。これは予想されることですか?Object2インスタンスのクリーンアップを強制して、各ループが新たに開始されるようにする方法はありますか?これは悪いプログラム設計ですか?

ありがとう!ライアン

4

4 に答える 4

5

ガベージコレクションは非常に信頼性が高いため、メモリリークが発生したり、無期限に増加したりすることはありません。

ただし、GCは、JVMが必要と判断した場合にのみ実行されるため、ループのすべての反復の最後に強制的に実行することはできません。

GCの実行時期に依存するコードを持つことは悪いコードです。

また、インスタンス数をどのように管理しているかわかりません。コンストラクターでインクリメントするのは簡単ですが、いつ再び減らすのですか?それは確かに自動的には起こりません。

于 2012-11-12T02:14:50.797 に答える
0

問題は、Object2のインスタンスが、各ループ反復の終了時にガベージコレクションを取得していないことです...。これは予想されることですか?

はい、そうです。JVMのデフォルトの動作は、最も効率的なときにガベージコレクターを実行することです。これは通常、「新しい」スペースがいっぱいになることを意味します。GCは確かに「熱心」ではなく、オブジェクトが到達不能になるとすぐにオブジェクトを再利用しようとはしません。

Object2インスタンスのクリーンアップを強制して、各ループが新たに開始されるようにする方法はありますか?

System.gc()ガベージコレクターを今すぐ実行するためのヒントとして呼び出すことができます。ただし、JVMはヒントを無視するように構成できます。

これは悪いプログラム設計ですか?

通常、を呼び出すのは悪い設計System.gc()です。GCの実行は比較的費用がかかり、(人間工学的な観点から)必要のないときに頻繁に実行することは非常に無駄です。

すぐに実行されるGCに依存するコードを書くことは常に悪い設計です。確かに、習慣の使用を必要とするものはすべて、finalize()大きな疑いを持って扱われるべきです。


私はあなたの本当の問題はこれだと思います:

....したがって、Object2の静的instancecount変数は、反復ごとに(メモリ使用量とともに)大きくなります。

これはある意味で真実です。しかし、最終的には、JVMはGCを実行するのに適した時期であると判断し、すべてのオブジェクトが再利用されます。これがGCの仕組みです。

あなたの本当の問題は(私が思うに)まだ回収されていないすべてのガベージオブジェクトを保持するためにかなりの量のメモリが必要であるという事実に不快感を覚えていることです。しかし、その反面、GC ...とアプリケーション...は、十分なメモリを使用できる場合、より高速に実行されます。驚いたことに、割り当てと再利用の両方が、GCが(たとえば)参照カウントを使用してオブジェクトができるだけ早く再利用されるようにする場合よりもはるかに高速です。


もう1つ注意すべき点は、インスタンスカウンターをデクリメントするには、ファイナライザーを使用する必要があるということです。これには、GCのオーバーヘッドが大幅に増加し、オブジェクトの最終的なリサイクルが遅くなるという不幸な副作用があります。

(メインGCは、オブジェクトがファイナライズ可能であることを認識し、後でファイナライズするためにキューに追加します。ファイナライズ可能なオブジェクトと到達可能なオブジェクトは、すぐに再利用できるオブジェクトのリストから削除されます。後でポイント、ファイナライズスレッドはキューを反復処理し、finalize各メソッドのメソッドを呼び出します。これによりオブジェクトが完全に到達不能になった場合、次のGC実行でオブジェクトが再利用されます。)

于 2012-11-12T03:11:51.653 に答える
0

static instancecount variable (among other static variables)

Object2の静的変数を確認します。いずれにせよObject2インスタンスを参照している場合、手動で削除しない限り、そのインスタンスがガベージコレクションされることはありません。

an object (Object1) whose constructor creates instances of other objects (Object2) and stores them in an ArrayList

そして、このArrayListはどこに格納され、いつクリアされますか?forループのこのリストからObject2を削除してみてください。

より多くのコードを表示できれば、デバッグが容易になります。

于 2012-11-12T02:21:00.717 に答える
0

みなさん、ありがとうございました!GCに依存しないようにコードを書き直しました。残念ながら、これは、ループの実行ごとにいくつかの静的変数を手動でクリアすることを意味しました。これについて何か厄介なように思われるので、将来的には、ループ内に静的変数を含むファクトリオブジェクト/メソッドを実行するコードに注意する必要があると思います。

これが私が皆さんから受け取ったいくつかの質問に対する答えです。繰り返しになりますが、どうもありがとうございました!

Thilo:コンストラクターを介してinstancecountをインクリメントしますが、instancecountを減らさないでください。これらは存在しませんが、それはデコンストラクターにとって適切なもののように思えます。それを減らすための適切な方法は何でしょうか?

エイドリアン:ループ内のArrayListをクリアしようとしましたが、成功しませんでした。ArrayListはObject1のフィールドです。

スティーブン:インスタンスカウントをデクリメントする方法についての上記の質問に答えたようですが、あなたが示唆したように、これは不要なオーバーヘッドを追加します。

Chamini2:投稿する前にforループでSystem.gc()を呼び出そうとしましたが、実行したくありません。どうやらこの方法は単なる提案です。

于 2012-11-13T02:45:23.913 に答える