19

Javaでは、私はそれについてあまり考えずに次のようなことをしました:

public class Main {

    public void run() {
        // ...
    }

    public static void main(String[] args) {
        new Main().run();
    }
}

しかし、最近、それが安全かどうか確信が持てなくなりました。結局のところ、Main作成後のオブジェクトへの参照はありません(参照はありthisますが、それは重要ですか?)ので、実行中にガベージコレクターがオブジェクトを削除する危険性があるようです。なにか。したがって、おそらくmainメソッドは次のようになります。

    public static void main(String[] args) {
        Main m = new Main();
        m.run();
    }

これで、最初のバージョンが機能することは間違いなく、問題は発生していませんが、すべての場合(特定のJVMだけでなく、できればそのような場合について言語仕様が述べていること)。

4

4 に答える 4

32

オブジェクトメソッドが実行されている場合、それは誰かがその参照を所有していることを意味します。したがって、メソッドの実行中はオブジェクトをGCすることはできません。

于 2013-01-01T15:30:37.690 に答える
3

ほとんどの場合、ガベージコレクションは透過的です。手動のメモリ管理の不要な複雑さを取り除くためにあります。したがって、収集されていないように見えますが、実際に発生することはより微妙です。

自明なことに、コンパイラはオブジェクトの構築を完全に排除するかもしれません。(コンパイラとは、javacよりも低レベルのコンパイラを意味します。バイトコードはソースの文字通りの音訳になります。)もっとわかりにくいことに、ガベージコレクションは通常、別々のスレッドで実行され、メソッドの実行中にアクセスされていないオブジェクトを実際に削除します。

これはどのように観察できますか?ファイナライザーの通常の容疑者。オブジェクトで実行されているメソッドと同時に実行される場合があります。synchronized通常、ファイナライザーと通常の方法の両方でブロックを使用してこの問題を回避します。これにより、必要な発生前の関係が導入されます。

于 2013-01-01T16:17:12.477 に答える
2

mは、参照が格納されている単なる変数です。これは、プログラマーが同じオブジェクトをさらに使用して同じオブジェクトにロジックを書き込むために使用されます。

実行中、プログラムはOP-CODES/INSTRUCTIONSに変換されます。これらの命令には、オブジェクトへの参照が含まれます(結局のところ、これはメモリの場所です)。mが存在する場合、オブジェクトの場所は間接参照を介してアクセスされます。mがない場合、参照はDIRECTです。

したがって、ここでは、参照変数の使用に関係なく、オブジェクトはCPUレジスタによって使用されています。

これは、実行フローがmain()関数のスコープ内に入るまで使用できます。

さらに、GCプロセスに従って、GCはオブジェクトがそれ以上使用されないことを確認すると、メモリからオブジェクトを削除するだけです。

すべてのオブジェクトには、何度も生き残るチャンスが与えられます(状況とアルゴリズムによって異なります)。チャンスの数が終わると、オブジェクトのみがガベージコレクションされます。

簡単に言えば、最近使用されたオブジェクトは、メモリにとどまる機会が与えられます。古いオブジェクトはメモリから削除されます。

だからあなたのコードを考えると:

public class Main {

public void run() {
    // ...
}

public static void main(String[] args) {
    new Main().run();
}
}

オブジェクトはガベージコレクションされません。

また、例として、匿名クラスの例を見てみてください。または、AWT/SWINGでのイベント処理の例。

そこには、このような多くの使用法があります。

于 2013-01-01T17:30:43.133 に答える
1

受け入れられた答えは正しくありません。オブジェクトをGCできるかどうかは、public void run() {// ...}メソッドにクラスインスタンス(this)への参照があるかどうかによって異なります。試す:

public class FinalizeThis {

    private String a = "a";

    protected void finalize() {
        System.out.println("finalized!");
    }

    void loop() {
        System.out.println("loop() called");
        for (int i = 0; i < 1_000_000_000; i++) {
            if (i % 1_000_000 == 0)
                System.gc();
        }
        // System.out.println(a);
        System.out.println("loop() returns");
    }

    public static void main(String[] args) {
        new FinalizeThis().loop();
    }
}

上記のプログラムは常に出力します

loop() called
finalized!
loop() returns

ただし、Java 8の場合、コメントを解除System.out.println(a)すると、出力は次のように変更されます。

loop() called
a
loop() returns

呼び出されたメソッドがインスタンス変数(this.a)を参照するため、今回はGCはありません。

あなたはこの答えを見ることができます

于 2021-06-05T04:15:44.277 に答える