落とし穴に注意してください!Java の内部クラスが外部クラスを保持すると、メモリ リークが発生する可能性があります。。。

導入

説明する

この記事では、Java の内部クラスが外部クラスを保持することによって発生するメモリ リークの原因と解決策を紹介します。

内部クラスが外部クラスを保持することでメモリ リークが発生するのはなぜですか?

非静的内部クラスは外部クラスを保持します。非静的内部クラスがどこかで参照されている場合、外部クラスも参照されます。外部クラスは、ガベージ コレクション中にリサイクルできません (外部クラスが使用されなくなった場合でも)他の場所)。

解決

他の場所にこの非静的内部クラスへの参照を保持させず、この非静的内部クラスで直接ビジネスを実行しないでください。

非静的内部クラスを静的内部クラスに変更します。内部クラスが静的に変更された後は、内部クラスが参照するオブジェクトまたはプロパティも静的である必要があるため、静的内部クラスは外部オブジェクトへの参照を取得できず、JVM のメソッド領域からのみ静的型参照を取得できます。

オープンソースで無料の Spring Boot 実践プロジェクトを推奨します。

https://github.com/javastacks/spring-boot-best-practice

なぜ外部授業を行う必要があるのでしょうか?

Java 言語では、非静的内部クラスには 2 つの主な機能があります。

  • 内部クラスが外部クラスでのみ使用される場合、匿名内部クラスはその存在を外部に知られないようにすることができるため、コードの保守作業が軽減されます。
  • 内部クラスが外部クラスを保持している場合、外部クラスの変数を直接使用できるため、次のコードに示すように、呼び出しを非常に簡単に完了できます。
package org.example.a;

class Outer{
    private String outerName = "Tony";

    class Inner{
        private String name;

        public Inner() {
            this.name = outerName;
        }
    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().createInner();
        System.out.println(inner);
    }
}

ただし、静的な内部クラスは、外部クラスとその非静的フィールドを保持できません。

たとえば、次の場合はエラーが報告されます。

package org.example.a;

class Outer{
    private String outerName = "Tony";

    static class Inner{
        private String name;

        public Inner() {
            this.name = outerName;
        }
    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().createInner();
        System.out.println(inner);
    }
}

エラーが報告されました:

例:外部授業の開催

コード

package org.example.a;

class Outer{
    class Inner {

    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().createInner();
        System.out.println(inner);
    }
}

ブレークポイントのデバッグ

内部クラスが外部クラスのオブジェクトへの参照を保持しており、それがフィールド「this$0」に保存されていることがわかります。

例: 外部クラスを保持しない

オープンソースで無料の Spring Boot 実践プロジェクトを推奨します。

https://github.com/javastacks/spring-boot-best-practice

package org.example.a;

class Outer{
    static class Inner {

    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().createInner();
        System.out.println(inner);
    }
}

ブレークポイントのデバッグ

内部クラスが外部クラスを保持しなくなっていることがわかります。

例: メモリリーク

導入

内部クラスが外部クラスへの参照を保持し、内部クラスが頻繁に使用されると、外部クラスの数が大量になります。このとき、外部クラスのデータを使用しなくても、外部クラスのデータが占有していた領域は解放されません。

この場所には、シミュレーション用に外部クラスに大量のデータが保存されます。

コード

package org.example.a;

import java.util.ArrayList;
import java.util.List;

class Outer{
    private int[] data;

    public Outer(int size) {
        this.data = new int[size];
    }

    class Innner{

    }

    Innner createInner() {
        return new Innner();
    }
}

public class Demo {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        int counter = 0;
        while (true) {
            list.add(new Outer(100000).createInner());
            System.out.println(counter++);
        }
    }
}

テスト

8,000 回以上実行するとメモリがオーバーフローしたことがわかります。

Macパソコンに変えたのですが、4000を超えたところでメモリがオーバーフローしてしまいました。

メモリリークのないソリューション

導入

内部クラスが静的に変更された後は、内部クラスが参照するオブジェクトまたはプロパティも静的である必要があるため、静的内部クラスは外部オブジェクトへの参照を取得できず、静的型の参照をメソッド領域からのみ取得できます。 JVM。

コード

package org.example.a;

import java.util.ArrayList;
import java.util.List;

class Outer{
    private int[] data;

    public Outer(int size) {
        this.data = new int[size];
    }

    static class Inner {

    }

    Inner createInner() {
        return new Inner();
    }
}

public class Demo {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        int counter = 0;
        while (true) {
            list.add(new Outer(100000).createInner());
            System.out.println(counter++);
        }
    }
}

テスト

400,000 回以上ループしてもメモリ オーバーフローが発生していないことがわかります。

出典: blog.csdn.net/feiying0canglang/article/details/121108201

最近のおすすめ人気記事:

1. 1,000 を超える Java 面接の質問と回答をまとめたもの (2022 年最新バージョン)

2.爆発的!Java コルーチンが登場します。

3. Spring Boot 2.x チュートリアルは完了です。

4.爆発的なカテゴリで画面を埋めるのをやめて、デコレータ モードを試してください。これがエレガントな方法です。

5. 『Java開発マニュアル(松山編)』が新しくリリースされましたので、お早めにダウンロードしてください!

良いと思ったら「いいね!」と「リツイート」を忘れずに!

おすすめ

転載: blog.csdn.net/youanyyou/article/details/132833525