3

NetBeans IDE を使用していますが、意味をなさない警告が表示されます。警告には、「コンストラクターでこれをリークしています」と記載されています。次のコードは基本的なセットアップです (問題に関係のないコードを削除しただけです)。Square基本的に、作成されたすべてのオブジェクトのリストを保持したいだけです。これは私が心配する必要がある警告ですか? それとも、状況によってはメモリリークの原因として考えられるだけですか?

いずれにせよ、これがリークと見なされる理由を誰かが説明できますか?

public class Square {
    private static ArrayList<Square> squares;

    public Square() {
        if(squares == null) {
            squares = new ArrayList<>();
        }

        squares.add(this); // I get a warning on this line
    }
}

これが単なる警告であることはわかっていますが、何が起こっているのかを完全に理解し、特定の状況に対して情報に基づいた選択を行うことができない限り、警告を無視したくありません。

ありがとう!

4

7 に答える 7

4

(全然答えになってないけど…)

作成したすべての正方形のリストをリストに維持することが目的である場合は、それを達成するためのより良い方法があります。

public class Square
{
    private static final List<Square> allSquares = new ArrayList<Square>();

    // Constructor: private!
    private Square() {}

    // Create a square
    public static Square newSquare()
    {
        Square ret = new Square();
        allSquares.add(ret);
        return ret;
    }
}

thisコンストラクターにはエスケープがないことに注意してください。

新しい正方形を作成するには、次のようにします。

Square mySquare = Square.newSquare();
于 2013-01-09T06:09:59.360 に答える
3

警告はガベージ コレクションに関するものではないと思いますが、これは確かに問題です。インスタンスが GC されることはありません (全体ClassLoaderが収集されない限り)。

警告はthis、コンストラクター内から別のメソッドに渡されていることを示しています。コンストラクターが終了する前に、コンストラクターに組み込まthisれているロジックに従って、必ずしも完全に形成され初期化されたオブジェクトであるとは限りません。コンストラクター内のすべてのことは、他の何かがオブジェクトを取得する前に発生することを意図しています。thisしかし、コンストラクターが終了する前に、別の何かが使用され始めています。それは驚くべきバグを引き起こす可能性があります。

于 2013-01-09T06:03:52.150 に答える
2

これがリークと見なされる理由を誰かが説明できますか?

squaresリストとリスト内のオブジェクトはガベージ コレクションされないため、(潜在的な) リークです。リストからオブジェクトを削除するか、リストをクリアまたは null にするコードが他にない場合、オブジェクトはリストを介してリークします。


おそらく、ガベージ コレクション言語のコンテキストで「メモリ リーク」が何を意味するのかを理解する必要があります。C や C++ などの言語では、オブジェクトが失われるとストレージ リークが発生します。つまり、オブジェクトを解放/破棄する必要があるコードが、そうすることに失敗します。ガベージ コレクション言語では、オブジェクトがまだ使用されているように見えるために GC がオブジェクトの解放/破棄に失敗すると、リークが発生します。つまり、GC はトレースによってオブジェクトを見つけることができます。


しかし、質問を読み直すと、Sean Owen に同意します。「コンストラクターでこれをリークしています」というメッセージは、コンストラクターが完了する前にコンストラクターがオブジェクトの参照を可視化しているという事実について話している可能性が最も高いです。これは「安全でない公開」とも呼ばれます。これは、陰湿な並行性バグの原因となる可能性があります。(シングル スレッド アプリケーションでも問題になる可能性があります。たとえば、Square のサブクラスを作成する場合...)

于 2013-01-09T06:01:41.203 に答える
1

免責事項:これは単なる推測です!

これが変更される唯一の場所である場合、各オブジェクトには常に少なくとも 1 つの参照が存在するため、オブジェクトがガベージ コレクションされないことsquaresを意味します。Squareもしそうなら、おそらくあなたの IDE はこれを見つけるのに十分賢いでしょう。

于 2013-01-09T06:00:50.880 に答える
1

コンストラクターで静的ArrayListに追加するとメモリリークが発生するのはなぜですか?

いいえ。それはあなたが得ている警告の根本的な原因ではありません。ただし、他にも複数の問題があります。

  1. thisコンストラクタの外に渡してはいけません。(これに従わないと、散発的な問題が発生する可能性があります)

  2. Squareクラスは、作成されたすべてのオブジェクトのリストを保持します。つまり、作成された各オブジェクトには、少なくとも参照が存在します。

    Square aSq = new Square(); // two references, aSq and reference in ArrayList
    new Square(); // one reference in ArrayList
    

    そのため、クラスがメモリに存在するまで、作成されたすべてのオブジェクトがガベージ コレクションされることはありません。したがって、メモリリークが発生します。

于 2013-01-09T06:12:18.887 に答える
0

静的変数は、ClassLoaders によって参照される Class オブジェクトによって参照されることを理解していると思います。したがって、ClassLoader 自体がガベージ コレクションの対象となるか、ClassLoader が何らかの方法で参照クラスを削除しない限り、ガベージ コレクションは行われません。したがって、コンストラクターが呼び出されるたびに、リストにデータを追加しているため、ガベージ コレクションはほとんど行われません。

于 2013-01-09T06:04:11.293 に答える
0

なんらかの理由で、これは悪い習慣だと思います。

OOP の存在理由は、一連のコントラクトのカプセル化です。そして、これらのコントラクトは、クラスのサブスクライバーに明確に表示される必要があります。

誰かが をインスタンス化するときnew Square()、インスタンス化がこのインスタンスを非ガベージ コレクション リストに追加していることは、プログラマには明らかではありません。

したがって、プログラマーである私は喜んで Square を頻繁にインスタンス化し、簡単にインスタンス化された Square のそれぞれへのすべての参照を意識的に破棄する限り、ガベージ コレクションが行われると自明に信じています。しかし、私は間違っています。私の意識的な努力にもかかわらず、どのインスタンスもガベージ コレクションされないからです。

ご存じのように、ガベージ コレクションによって、プログラマーは習慣的な近道を行うことができました。たとえば、次の while 構造は、単純にインスタンス化されたオブジェクトの単純化を例示しています。プログラマーは、前のインスタンスがガベージ コレクションされることを知っているため、String ins を繰り返し再インスタンス化することに何の不安もありません。

String ins = new String();
while(c != null && ins != null) {
  ins = new String();
  readInputInto(ins);
}

ただし、文字列を正方形に置き換えて、一般的なプログラマーの手に渡してください。プログラマーは、String と同じガベージ コレクション可能性を想定します。

したがって、コンストラクターで多くのことをしようとすること、特にコンストラクター内で大きな影響を与えるアクションを隠すことはお勧めできません。

コンストラクターの外側のリストにインスタンスを追加するだけです。

于 2013-01-09T06:30:03.143 に答える