4

Javaでキューを実装していて、iniと呼ばれる最初のノードへの参照と、lastと呼ばれる最後のノードへの参照があるとします。ここで、オブジェクトをキューに挿入し始めます。ある時点で、キューをクリアする操作が必要だと判断しました。それから私はこれをします:

ini = null;
last = null;

メモリリークが発生していますか?iniとlastの間のノードはすべてまだチェーンされており、データが残っていると思いますが、同時にガベージコレクターがあります。

別の方法は、各要素にアクセスしてから次のノードへの参照をnullにすることですが、明示的にdeleteを使用しないことを除いて、基本的にC++と同じように実行します。

4

5 に答える 5

19

キュー内のアイテムがコード内の他の場所で参照されていない限り、ガベージコレクターはそのメモリを再利用できます。Javaでポインタをnullに設定することは、mallocされたポインタをnullに設定すると解放されないCの場合と同じではありません。Javaでは、メモリに到達できなくなったときにメモリが再利用されます。JNIを介してネイティブコードを使用していない限り、Java(C / C ++の意味で)でメモリリークは発生しません。

単純なガベージコレクターは、オブジェクトへの参照数をカウントし、参照カウントがゼロに達したときにそのオブジェクトの割り当てを解除するだけですが、参照サイクル(A-> B、A-> B-> C)を処理することはできません。 -> Aなど)。Java GCアルゴリズムは、システム内のすべてのオブジェクトの参照グラフを作成する活性テストを実行します。GCはグラフトラバーサルを実行し、到達できないノード(オブジェクト)は未使用としてマークされ、再割り当てに使用できます。グラフのルート(トラバーサルの開始点)には、スレッドスタック上の変数、静的変数、およびJNIを介してネイティブコードによって保持される参照が含まれます。詳細はこちら: http: //java.sun.com/developer/Books/performance/performance2/appendixa.pdf

参照リークが発生する可能性はあります。これは、必要以上にオブジェクトへの参照を保持している状況を指します。例えば:

public class Stack {
  private final Object[] stack = new Object[10];
  private int top = 0;
  public void push(Object obj) {stack[top++] = obj;}
  public Object pop() {return stack[top--]; }
}

オーバーフロー/アンダーフローの可能性を無視して、Stack.pop()を呼び出した後も、配列メンバー変数には、返されたオブジェクトへの参照が含まれています。周囲のStackインスタンスが参照されなくなるまで、そのオブジェクトがガベージコレクションされるのを防ぎます。これは、メモリを再利用できるように変数をnullに設定する必要があるまれな例の1つです。

public Object pop() {Object ret = stack[top]; stack[top--] = null; return ret;}
于 2008-12-20T22:43:15.450 に答える
3

それはうまくいくでしょう。GCはノードに到達できないことを検出するため、すべてのノードがクリーンアップされます。

于 2008-12-20T22:44:00.707 に答える
3

はい、GCはその場合に機能します。ただし、head と tail の間の要素は生き残って古い世代空間に入り、フル GC 中に収集される可能性があります。ご存知のように、フル GC は高価です。パフォーマンスに関する限り、それらを無効にする方が優れています。

java.util.LinkedList の clear() メソッドがどのように実装されているかがわかります。

public void clear() {
    Entry<E> e = header.next;
    while (e != header) {
        Entry<E> next = e.next;
        e.next = e.previous = null;
        e.element = null;
        e = next;
    }
    header.next = header.previous = header;
    size = 0;
    modCount++;
}

http://tech.puredanger.com/2009/02/11/linkedblockingqueue-garbagecollection/で問題に触れています。

于 2009-02-27T10:32:03.863 に答える
0

メモリ リークが疑われる場合は、メモリ プロファイラーを使用して、オブジェクトがどのように保持されているかを確認することをお勧めします。このようなツールを使用すると、急速なメモリ リークが明らかになるため、リークが疑われるテストを作成し、それを何度も繰り返すと、リークと、オブジェクトが保持されている理由を確認できます。

于 2009-02-27T21:41:48.950 に答える
-1

次のコードは、リスト構造の途中に迷子になったハンドルがあると、GC が完全にクリーンアップされないようにする方法を示しています。

import java.lang.ref.*;

public class MemoryLeak1 {

    MyListItem leakedItem = null;
    WeakReference[] refs = null;

    public static void main(String[] args) {
        WeakReference ref = null;
        MyListItem item = null;
        MemoryLeak1 leak = new MemoryLeak1();
        int i;

        leak.doit(); // create a memory leak
        System.gc(); // force the gc to run;

        // At this point the list has been explicitly cleared,
        // has gone out of scope, and the GC has run.
        // However, leak.leakedItem is still holding a
        // reference to an item in the list, so anything
        // reachable from that item is still alive.

        // show what's still around...
        for (i = 0; i < 10; i++) {
            ref = leak.refs[i];
            item = (MyListItem)ref.get();
            if (item == null) { System.out.println("" + i + " = null"); }
            else { System.out.println("" + i + " = " + (String)item.thing); }
        }
        System.out.println("---------------------");

        // now let's free some additional items...
        for (i = 1; i <= 3; i++) {
            item = leak.leakedItem;
            leak.leakedItem = item.next;
            leak.leakedItem.prev = null;
            item.prev = null;
            item.next = null;
        }
        item = null;

        System.gc(); // force the gc to run again

        // this time we should get fewer items
        for (i = 0; i < 10; i++) {
            ref = leak.refs[i];
            item = (MyListItem)ref.get();
            if (item == null) { System.out.println("" + i + " = null"); }
            else { System.out.println("" + i + " = " + (String)item.thing); }
        }
        System.out.println("---------------------");

        // now clear the last reference
        leak.leakedItem = null;

        System.gc(); // force the gc to run again

        // this time we should none
        for (i = 0; i < 10; i++) {
            ref = leak.refs[i];
            item = (MyListItem)ref.get();
            if (item == null) { System.out.println("" + i + " = null"); }
            else { System.out.println("" + i + " = " + (String)item.thing); }
        }
        System.out.println("---------------------");
    }

    public void doit() {
        this.refs = new WeakReference[10];
        MyList list = new MyList();
        MyListItem item = null;

        // add strings to the list.
        // set each into the array of soft refs 
        // set a ptr to the 6th item in an instance variable
        for (int i = 0; i < 10; i++) {
            item = new MyListItem();
            item.thing = new String("string" + i);
            list.insert(item);
            if (i == 5) this.leakedItem = item;
            this.refs[i] = new WeakReference(item);
        }

        // clear the list, but don't clear the
        // additional ptr to the 6th item
        list.clear();
    }
}

class MyList {
    MyListItem head = null;
    MyListItem tail = null;

    void clear() {
        head = null;
        tail = null;
    }

    void insert(MyListItem item) {
        if (head == null) {
            // empty list
            item.next = null;
            item.prev = null;
            tail = item;
            head = item;
        }
        else if (head == tail) {
            // one item in list
            item.next = head;
            item.prev = null;
            tail = head;
            head = item;
        }
        else {
            // multiple items in list
            item.next = head;
            item.prev = null;
            head = item;
        }
    }

    MyListItem remove() {
        MyListItem item = tail;
        if (item != null) {
            tail = item.prev;
            if (tail == null) {
                head = null;
            }
            else {
                tail.next = null;
            }
            item.next = null;
            item.prev = null;
        }
        return item;
    }
}

class MyListItem {
    MyListItem next = null;
    MyListItem prev = null;
    Object thing = null;
}
于 2008-12-21T02:07:50.967 に答える