目次
Java のメモリ リーク問題
添付: メモリ リークの典型的な状況
ホームページ Java &#&チュートリアル Javaのメモリリーク問題事例分析

Javaのメモリリーク問題事例分析

May 23, 2023 pm 06:46 PM
java

Java のメモリ リーク問題

いわゆるメモリ リークとは、プログラムで使用されなくなったオブジェクトまたは変数がメモリ内で占有されていることを意味します。

Java にはガベージ コレクション メカニズムがあり、オブジェクトが参照されなくなったとき、つまりオブジェクトが孤立したとき、オブジェクトはガベージ コレクタによってメモリから自動的にクリアされます。 。

Java にはガベージ コレクション メカニズムがあるのに、メモリ リークの問題が依然として存在するのはなぜでしょうか?

一部のオブジェクトはガベージ コレクターで処理できず、これらのオブジェクトが常に JVM メモリを占有することになり、メモリ リークが発生するだけです。

Java はガベージ コレクション管理に有向グラフを使用するため、参照サイクルの問題を排除できます。たとえば、相互に参照する 2 つのオブジェクトがある場合、それらのオブジェクトにアクセスできない限り、たとえば、次のコードは、この場合のメモリのリサイクルを確認できます。

import java. io.IOException;
public class GarbageTest {

    public static void main(String[] args) throws IOException {
        try {
            // TODO Auto-generated method stub
            gcTest();
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("has exited gcTest!");
        System.in.read();
        System.in.read();
        System.out.println("out begin gc!");
        for (int i = 0; i < 100; i++) {
            System.gc();
            System.in.read();
            System.in.read();
        }
    }

    private static void gcTest() throws IOException {
        System.in.read();
        System.in.read();
        Person p1 = new Person();
        System.in.read();
        System.in.read();
        Person p2 = new Person();
        p1.setMate(p2);
        p2.setMate(p1);
        System.out.println("before exit gctest!");
        System.in.read();
        System.in.read();
        System.gc();
        System.out.println("exit gctest!");
    }

    private static class Person {
        byte[] data = new byte[20000000];
        Person mate = null;

        public void setMate(Person other) {
            mate = other;
        }
    }

}
ログイン後にコピー

Java でのメモリ リーク: 存続期間の長いオブジェクトが存続期間の短いオブジェクトへの参照を保持している場合、メモリ リークが発生する可能性があります。存続期間の短いオブジェクトはもう必要ありませんが、長命 循環オブジェクトはその参照を保持しており、リサイクルすることはできません。これは、Java でメモリ リークが発生するシナリオです。平たく言えば、プログラマはオブジェクトを作成した後、それを再度使用することはありませんが、オブジェクトは常に使用されます。参照とは、このオブジェクトは役に立たないが、ガベージ コレクターによってリサイクルできないことを意味し、これは Java でメモリ リークが発生する可能性がある状況です。

たとえば、キャッシュ システムでは、オブジェクトをロードしてキャッシュ (たとえば、グローバル マップ オブジェクト内) に置きます。その後、それを再度使用することはありません。このオブジェクトの値は、次の方法で参照されます。キャッシュがありますが、もう使用されませんので、便利にご利用ください。

Java でメモリ リークをチェックするには、プログラムの最後まですべての分岐を実行させてから、オブジェクトが使用されているかどうかを確認する必要があります。使用されていない場合は、そのオブジェクトが使用されていると判断できます。メモリリークです。

外部クラスのインスタンス オブジェクトのメソッドが内部クラスのインスタンス オブジェクトを返す場合、外部クラスのインスタンス オブジェクトが使用されなくなっても、内部クラスのオブジェクトは長期間参照されますが、内部クラスはクラスの Instance オブジェクトの外側に存続するため、この外部クラス オブジェクトはガベージ コレクションされず、これによってもメモリ リークが発生します。

次のコンテンツはインターネットからのものです (主な機能は、スタック内の要素を配列から完全に削除するのではなく、要素をクリアすることですが、保存されている総量を減らすことです。私はこれよりもうまく書くことができます、要素を削除するときは、要素を配列からも消去します。その要素の位置の値を null に設定するだけです)

このスタックより古典的な例は本当に思いつきません。他の人の例を引用しなければなりません。以下の例は私が考えたことではなく、本で見たものです。もちろん、本で見ていなかったとしても、しばらくしてから自分で考えたかもしれません。でもその時は自分で考えたと言いましたが、誰も信じてくれませんでした。

public class Stack {
    private Object[] elements = new Object[10];
    private int size = 0;

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0) throw new EmptyStackException();
        return elements[--size];
    }

    private void ensureCapacity() {
        if (elements.length == size) {
            Object[] oldElements = elements;
            elements = new Object[2 * elements.length + 1];
            System.arraycopy(oldElements, 0, elements, 0, size);
        }
    }
}
ログイン後にコピー

上記の原則は非常に単純です。お金の山に 10 個の要素が追加され、お金の山は空で欲しいものは何もありませんが、それらがすべてポップアップした場合、これはリサイクルできないオブジェクトです。これはメモリ リークの 2 つの条件を満たします。役に立たないため、リサイクルできません。しかし、たとえそのようなものが存在したとしても、それが必ずしも何らかの結果をもたらすとは限りません。この山積みのお金の使用が減ったとしても、それは数Kのメモリを無駄にするだけです。とにかく、私たちのメモリはすでにGを超えています、それでどのような影響があるでしょうか?それに、これはすぐにリサイクルされるのに、それはどうでもいいのですか?以下に 2 つの例を見てみましょう。

class Bad {
    public static Stack s = new Stack();
    static {
        s.push(new Object());

        s.pop(); //这里有一个对象发生内存泄露

        s.push(new Object());//上面的对象可以被回收了,等于是自愈了
    }
}
ログイン後にコピー

静的であるため、プログラムが終了するまで存在しますが、自己修復機能があることもわかります。つまり、スタックに最大 100 個のオブジェクトがある場合、オブジェクトは最大 100 個しかありません。リサイクルできません。実際、これは簡単に理解できるはずです。スタックは内部的に 100 個の参照を保持します。最悪のシナリオは、それらがすべて役に立たないことです。新しい進捗を追加すると、以前の参照は自然に消えます。

メモリ リークの別の状況: オブジェクトが HashSet コレクションに格納されている場合、ハッシュ値の計算に関与するオブジェクト内のフィールドは変更できません。それ以外の場合、オブジェクトは変更されます。値が異なります。この場合、contains メソッドがオブジェクトの現在の参照をパラメーターとして使用して HashSet コレクションからオブジェクトを取得したとしても、見つからないオブジェクトが返されます。その結果、HashSet コレクションから現在のオブジェクトを個別に削除できなくなり、メモリ リークが発生します。

添付: メモリ リークの典型的な状況

(1) データ構造によって引き起こされる短期的なメモリ リークの問題。次のコードを参照してください。

public class Stack{  
      private Object[] element=new Object[10];  
      private int size=0;  
        
      public void push(Object ele){  
             ensureCapacity();  
             element[size++]=ele;  
      }  
  
      public Object pop(){  
             if(size==0) throw new EmptyStackException();  
             return element[--size]; //短暂造成内存泄露  
      }  
  
      private void ensureCapacity(){  
             if(element.length==size){  
                     Object[] oldElement=element;  
                     element=new Object[size*2+1];  
                     System.arraycopy(oldElement,0,element,0,size);  
             }  
      }  
}
ログイン後にコピー

上記のコードはポップします。 () 毎回 Stack は毎回要素をポップアップします。新しい要素を追加する前に、実際にはポップされたオブジェクトを指す参照 element[x] がまだ存在するため、GC はそれをガベージ コレクションしません。新しい要素をプッシュするときに element[x]=newObject を設定することによってのみ、以前に作成されたオブジェクトをリサイクルできます。上記の Pop() メソッドを次のコードに変更する方がはるかに安全です:

public Object pop(){  
       if(element.length==size) throws EmptyStackException();  
       Object o=element[--size];  
       elements[size]=null;  //使得GC有机会回收这个对象  
       return o;  
}
ログイン後にコピー

以上がJavaのメモリリーク問題事例分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルの量を見つけるためのJavaプログラム カプセルの量を見つけるためのJavaプログラム Feb 07, 2025 am 11:37 AM

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Feb 07, 2025 pm 12:11 PM

Spring Bootは、Java開発に革命をもたらす堅牢でスケーラブルな、生産対応のJavaアプリケーションの作成を簡素化します。 スプリングエコシステムに固有の「構成に関する慣習」アプローチは、手動のセットアップを最小化します。

See all articles