Каковы Поколения в Сборке "мусора"?

Я не понимаю, какие "поколения" находятся в контексте Сборки "мусора". Кто-то может объяснить простыми словами?

46
задан Mark Amery 12 April 2019 в 19:34
поделиться

2 ответа

Здесь есть две возможности для проблем:

  • Новые предметы могут быть немедленно забыты, потому что вы очистите и создадите новый список. Это проблема? В основном, если AddElement и ClearList вызываются одновременно, у вас есть условие гонки: либо элемент окажется в новом списке, либо в старом (забытом).
  • Список < T > небезопасен для многопоточных мутаций, поэтому, если два разных потока одновременно вызывают AddElement , результаты не гарантируются

Учитывая, что вы получаете доступ к общему ресурсу, я лично держу блокировку при доступе к нему. Вам все еще нужно рассмотреть возможность очистки списка непосредственно перед/после добавления предмета.

EDIT: Мой комментарий о том, что это нормально, если вы добавляете только из одного потока, уже был несколько сомнительным, по двум причинам:

  • Возможно (я думаю!), что вы можете в конечном итоге попытаться добавить в список < T > , который еще не был полностью построен. Я не уверен, и модель памяти .NET 2.0 (в отличие от модели в спецификации ECMA) может быть достаточно сильной, чтобы избежать этого, но это сложно сказать.
  • Возможно, что поток добавления не «увидит» изменение переменной list немедленно и все равно добавит в старый список. Действительно, без какой-либо синхронизации, он может видеть старое значение навсегда

Когда вы добавляете «итерацию в GUI» в микс он становится действительно сложным - потому что вы не можете изменить список во время итерации. Наиболее простым решением является, вероятно, предоставление метода, который возвращает копию списка, и пользовательский интерфейс может безопасно выполнять итерацию над этим:

class A
{
    private List<SomeClass> list;
    private readonly object listLock = new object();

    private void ClearList()
    {
        lock (listLock)
        {
            list = new List<SomeClass>();
        }
    }

    private void AddElement()
    {
        lock (listLock)
        {
            list.Add(new SomeClass(...));
        }
    }

    private List<SomeClass> CopyList()
    {
        lock (listLock)
        {
            return new List<SomeClass>(list);
        }
    }

}
-121--4631686-

Да - возможно,. На самом деле, если их действительно называют одновременно, это весьма вероятно.

Кроме того, существует вероятность возникновения проблем при одновременном выполнении двух отдельных вызовов addElement.

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

Грубая стратегия блокировки вокруг этого поможет. Что-то вроде:

class A
{
    static object myLock = new object()
    List<SomeClass> list;

    private void clearList()
    {
        lock(myLock)
        {
          list = new List<SomeClass>();
        }

    }

    private void addElement()
    {
        lock(myLock)
        {
          list.Add(new SomeClass(...));
        }
    }
}
-121--4631687-

Из Общие сведения о сборе мусора в .NET

Поколения

Сборщик мусора поколений собирает недолговечные объекты больше часто, чем более длинные живые. Недолговечные объекты хранятся в первое поколение, поколение 0. более долговечные объекты вставляются в высших поколений, 1 или 2. сборщик мусора работает больше часто в низших поколениях чем в высших.

При первом создании объекта он в генерацию 0. Когда поколение 0 заполнено, мусор вызывается коллектор. Объекты, которые пережить сбор мусора в первое поколение продвигается на следующее высшее поколение, поколение 1.Объекты, которые выживают мусор коллекция в поколении 1 повышен до следующего и самого высокого генерация, генерация 2. Это алгоритм работает эффективно для мусорный сбор объектов, как он быстро. Обратите внимание, что поколение 2 самое высокое поколение, которое поддерживается сборщиком мусора.

Сбор мусора в поколениях .NET

При выделении памяти управляемая куча быстрая, сам GC может занять некоторое время. Принимая это во внимание выполнено несколько оптимизаций для повышения производительности. ГХ поддерживает концепцию поколений, исходя из предположения, что дольше объект находился в куче, чем дольше он, вероятно, останется там. При назначении объекта на куча, которой она принадлежит в поколении 0. Каждый мусорный сбор, который объект выживает увеличивает генерация на 1 (в настоящее время самый высокий поддерживается генерация 2). Очевидно, это быстрее для поиска, и мусор собирают подмножество всех объекты в куче, так что GC имеет вариант сбора только генерации 0, 1 или 2 объекта (или что угодно комбинация, которую он выбирает, пока не получит достаточный объем памяти). Даже пока сбор только более молодых объектов GC может также определить, имеют ли старые объекты ссылки на новые объекты для обеспечения что он не игнорирует непреднамеренно используемые объекты.

53
ответ дан 26 November 2019 в 20:27
поделиться

В «Pro C # 2008» есть хорошее описание:

  1. Поколение 0 идентифицирует вновь созданный объект, который никогда не был помечен для коллекции
  2. Поколение 1 идентифицирует объект, который пережил сборщик мусора (помечен для сбора, но не удален, поскольку было достаточно места в куче)
  3. Поколение 2 идентифицирует объект, который пережил более одного цикла сборки мусора.
20
ответ дан 26 November 2019 в 20:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: