ごみ回収の考え(一)

3124 ワード

プログラミング言語が交代して今まで、ゴミ回収をしない言語を使ったことがない人はほとんどいません.一方、Cなどの言語ではメモリ管理が困難であるため、さらに重要なのは言語が高級であればあるほど、実際の業務論理を重視し、メモリ管理に関するコードが頻繁に業務に混在しているため、それほど自然ではありません.
ごみ回収のプログラミング体験はありません
#include <stdio.h>
#include <stdlib.h>

struct node {
  int value;
  struct node2* pnode2;
};

struct node2 {
  int value;
};

int main() {
    struct node* _node = (struct node*) malloc(sizeof(*_node));
    _node->pnode2 = (struct node2*) malloc(sizeof(struct node2));
    // Do something ...
    free(_node->pnode2);
    free(_node);
    return 0;
}

コードがこのように簡単なこのプログラムでは、自分がメモリを申請したり、メモリを回収したりする手間が表示されます.少し規模のあるプログラムでは、大量のダイナミックメモリの割り当てと解放が使用されると考えてみてください.プログラマーは、メモリの管理、メモリの漏洩の防止、メモリのデバッグの問題に大きな手間をかけなければなりません.
ごみ回収:メモリの自動管理
ごみの回収があった後、プログラマーをメモリ管理の煩雑さから救い出し、プログラマーがビジネスコードにもっと力を入れることができます.
public class Node {

  class Node2 {
  }

  private Node2 node2;

  public Node() {
    this.node2 = new Node2();
  }

  public static void main(String[] args) {
    Node node = new Node(); // this is node 1.

    node = new Node(); // this is node 2.
  }
}

ユーザは、メモリが解放されているかどうかに関心を持つ必要はありません.これらは、解放する参照が依然として到達しない限り、ゴミは常に回収されます.
ごみ回収の条件
1つのオブジェクトAが他のオブジェクトBを参照するので、オブジェクトAを回収する場合、そのメンバーBも再帰的に「解放」されるべきである.ここで「解放」は回収を試みることを意味するが、このメンバーBを参照するのはAだけではない可能性が高い.このような場合、盲目的にBを回収することは他のオブジェクトに影響を与え、いくつかのプログラムエラーをもたらすため、「解放」はAがBを参照しないことを宣言するだけである.Bが回収するかどうかは、ゴミ回収機に任せて判断します.では、上記の手順に従って、いくつかの必須要素があります.
  • オブジェクト参照状況の追跡は、参照状況に基づいてオブジェクトが回収すべきかどうかを判断することができ、利用可能な参照がある場合、オブジェクトを回収すべきではなく、プログラムの潜在的な異常をもたらす.
  • オブジェクトタイプ情報オブジェクトの回収が確認された場合、そのオブジェクトが属するタイプに基づいてメンバーオブジェクトインデックスを取得するメンバーオブジェクトの回収も試みる必要があります.

  • ごみ回収アルゴリズム
    ごみ回収が直面する挑戦ごみ回収は本質的にすべての対象に対して存在性判断を行い、ごみ回収の性能は対象の増加に伴って増加する.対象を探し出すのは回収可能な根拠である.ごみ回収を引き起こす条件は、メモリが不足していることが多く、ごみ回収器はメモリの破片をできるだけ減らし、メモリの申請をできるだけ満たすことができます.これらの問題はすべてごみ回収アルゴリズムが直面しなければならない.
    リファレンスカウントアルゴリズム
    リファレンスカウントは、オブジェクトのリファレンス回数(Reference count)を維持し、リファレンス回数がゼロの場合、このオブジェクトは回収されるべきです.
    Object obj  = new Object();  // obj: refCount = 1
    Object obj2 = obj;           // obj: refCount = 2, obj2: refCount = 2
    obj         = null;          // obj: refCount = 1, obj2: refCount = 1
    obj2        = null;          // obj: refCount = 0, obj2: refCount = 0

    ここでobjであろうとobj 2であろうと、それらはスタック上のメモリポインタを指すだけであり、ここでのrefCountは実際にはスタック上のnewによって生成されたメモリの参照回数を記述する.このようなカウント方法でメモリを解放するのは、直接簡単ですが、クロスリファレンスという危険性があります.
    public class Sample {
        class B {
            A a;
        }
        class A {
            B b;
        }
    
        public static void main(String[] args) {
            B b = new B();  // b: refCount = 1
            A a = new A();  // b: refCount = 1, a: refCount = 1
            b.a = a;        // b: refCount = 1, a: refCount = 2
            a.b = b;        // b: refCount = 2, a: refCount = 2
            a = null;       // b: refCount = 2, a: refCount = 1
            b = null;       // b: refCount = 1, a: refCount = 1
            // Memory Leaks...
        }
    }

    2つのオブジェクトが交差して参照され、最後にメンバー変数が手動で解放されなければ、2つのオブジェクトの最後のそれぞれの参照回数はゼロではなく、回収が困難です.
                                              ....