Когда ИМЕННО является объектом, подходящим для сборки мусора в C #? - PullRequest
8 голосов
/ 16 января 2012

Итак, я знаю основы: объект пригоден для сборки мусора, когда он более недоступен для корня (т. Е. Сильная ссылка либо из локальной переменной в кадре стека, либо из статической ссылки)

У меня есть вопрос об этой потенциальной оптимизации, когда, даже если на объект ссылаются из локальной переменной, он может собирать мусор в любой точке функции, на которую больше не ссылаются переменные.Во-первых - кажется, что существующие реализации C # не делают этого - и 2.0, и 4.0, кажется, поддерживают локальные ссылки «живыми», пока фрейм стека не будет разрушен.Но - я также хотел бы написать код, который по-прежнему устойчив, если и когда сборка мусора будет оптимизирована в более поздних версиях CLR.

Итак, без лишних слов, вот несколько иллюстраций кода:

class Foo 
{
  ...
}
class Program
{
    public static void fxn1(int blah) 
    {
      ...
    }
    public static void fxn2(Foo foo)
    {
      ...
    }
    public static int ToInt(Foo foo)
    {
      ...
    }
    public static void Main()
    {
      ...
      Foo foo = new Foo();
      fxn2(foo); // I THINK foo may not be GC'ed until fxn2 returns...
        // I THINK foo may be GC'ed here, even though CLR2.0 and CLR4.0 don't...
        //  (experiment shows CLR 2.0 and 4.0 leave foo "live" until Main returns)
      fxn2(new Foo()); // I THINK the argument can't be GC'ed until fxn2 returns...
        // I KNOW that even CLR2.0 and CLR4.0 will GC the argument after the return...
      fxn1( ToInt(new Foo()) ); // I KNOW that new Foo is GC'able even within fxn1...
    }
}

Таким образом, в конечном счете, правила для существующих CLR выглядят так: 1. любой объект является «живым» на время вызова функции, для которого он является непосредственным аргументом 2. любой объект является «живым» на времявызов функции, если на него ссылается локальная переменная стека, которая не переназначена.(даже если на переменную стека нельзя ссылаться для нескольких инструкций в конце функции)

Тем не менее - очевидно, C # оставляет за собой право изменить (2), чтобы объект был «живым» вплоть до последнегоиспользование ссылки внутри функции.

Это будет означать:

Foo foo = new Foo();
Foo foo2 = new Foo();
fxn2(foo); // foo is NOT GC'able until fxn1 returns?
   // foo IS GC'able from here on? (b/c no further uses of local "foo"?)
fxn2(foo2); // foo2 is NOT GC'able within fxn2 ?
fxn1(ToInt(foo2)); // foo2 IS GC'able within fxn1 ? (existing CLR does not GC foo2)

Есть ли в спецификации ECMA что-нибудь, что подробно описывает право на сборку мусора?

Ответы [ 3 ]

6 голосов
/ 16 января 2012

Ну, здесь невозможно дать общий ответ, так как когда все действительно становится подходящим для GC, полностью зависит от реализации вашей среды выполнения.

Единственное, чему вы можете доверять, - это гарантиям, т. Е. До тех пор, пока на объект ссылаются из стека, он не будет собран.

Вы не можете сказать из кода, когда локальная переменная удаляется из стека, хотя - это подвержено оптимизации компилятора - как в статическом компиляторе, так и в джиттере.

Так что, каким бы ни был точный ответ, теперь может не быть уже после следующего незначительного обновления вашей среды выполнения - обычно лучше написать код, который не зависит от таких тонкостей, который может быть обнаружен только экспериментом, и вместо этого полагается только на гарантии времени выполнения.

1 голос
/ 30 января 2012

@M.Babcock - Спасибо за ссылку на спецификацию ECMA!На самом деле 8.4 был слишком общим, но ответ, который я искал, был в 10.9 - и он идентичен Java - когда на переменную больше нельзя ссылаться каким-либо возможным будущим путем кода, тогда она считается пригодной для сборки мусора - что означает, чтохотя существующая реализация clr, по-видимому, ограничивает время жизни локальной переменной в стеке, нет никакой гарантии, что сторонние или будущие реализации сделают это.

0 голосов
/ 30 января 2012

Вы ссылаетесь на идею потенциальной оптимизации, собирая объект раньше.
Я не считаю это оптимизацией.

Это не так, как будто компьютер работает быстрее или лучше, если у него больше свободной памяти.

Либо распределение прошло успешно, либо не удалось.
Если это успешно, процесс работает нормально.
Если это не удастся, процесс окажется в беде.
(что-нибудь от тривиальной проблемы, от которой она может избавиться, до глубокой проблемы, которая приводит к завершению процесса)

Я просто не вижу смысла быть более агрессивным в отношении Г.С. как вы описываете. Это поможет только в граничном случае, когда вы уже работаете с 99,99% выделенной памяти. И в этом случае вы глубоко погружаетесь в виртуальную память и безумно перемещаетесь на диск.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...