GC.collect () достижимость объекта - PullRequest
2 голосов
/ 23 апреля 2011

Объекты, на которых больше нет ссылок, не могут быть немедленно собраны мусором с помощью GC.collect (), однако это промежуточный вызов, например, new, writeln или Thread.sleep сделает объект без ссылки доступным с помощью GC.collect ().

import std.stdio;
import core.thread;
import core.memory;

class C
{
    string m_str;
    this(string s) {this.m_str = s;}
    ~this() { writeln("Destructor: ",this.m_str); }
}

void main()
{
    {
        C c1 = new C("c1");
    }   
    {
        C c2 = new C("c2");
    }
    //writeln("Adding this writeln means c2 gets destructed at first GC.collect.");
    //Thread.sleep( 1 ); // Similarly this call means c2 gets destructed at first GC.collect.
    //int x=0; for (int i=0; i<1000_000_000;++i) x+=2*i; // Takes time, but does not make c2 get destructed at first GC.collect.
    GC.collect();
    writeln("Running second round GC.collect");
    GC.collect();
    writeln("Exiting...");
}

Приведенный выше код возвращает:

Разрушитель: c1
Бег второй тур GC.collect
Деструктор: с2
Выход ...

Может кто-нибудь объяснить эту достижимость объектов во время сбора мусора?

1 Ответ

6 голосов
/ 23 апреля 2011

Я не знаком с деталями сборки мусора D, но общая техника состоит в том, чтобы начинать со всех «корневых указателей», чтобы выяснить, какие объекты являются живыми.Когда все скомпилировано в машинный код, это означает, что он начинается со стека вызовов функций и регистров ЦП.

Приведенный выше код может компилироваться в нечто вроде:

$r0 = new C("c1")
$r0 = new C("c2")
GC.collect()
writeln("Running second round GC.collect")
GC.collect()
writeln("Exiting...")

Когда первыйGC.collect() больше нет ссылок на первый объект (так как $r0 был перезаписан).И хотя второй объект не используется, в $r0 все еще есть указатель на него, поэтому GC консервативно предполагает, что он достижим.Обратите внимание, что компилятор мог предположительно очистить $r0 после того, как переменная c2 выйдет из области видимости, но это сделает код более медленным.

Когда выполняется первый вызов writeln, он, вероятно, использует регистр $r0 внутренне и поэтому очищает ссылку на второй объект.Вот почему второй объект восстанавливается после второго вызова GC.collect().

...