Почему никакой Подсчет ссылок + Сборка "мусора" в C#?

То есть, вы хотите иметь доступ к соответствующему списку, основываясь на передаваемом значении env? Если они представляют собой статические списки, как вы показываете, проще всего было бы поместить их в словарь:

ENV_DICT = {
    "UPE_ENV": ['AMPOMSU01','AMPOAGU01','ampwt12u01','AMPDSU01'],
    "DEV_ENV": ['AMPOMSD01','AMPOAGD01','ampwt12d01','AMPDST01']
}

Затем вы могли бы извлечь его из этого слова:

env_list = ENV_DICT[env + '_ENV']
startOVD('start',env_list[3])

всегда вызывайте startOVD одним и тем же способом, независимо от значения env, вам не нужен оператор if.

55
задан Community 23 May 2017 в 10:31
поделиться

8 ответов

Брэд Абрамс отправил электронное письмо от Брайана Гарри , написанное во время разработки среды .Net. В нем подробно описаны многие причины, по которым подсчет ссылок не использовался, даже когда одним из первых приоритетов было сохранение семантической эквивалентности с VB6, который использует подсчет ссылок. Он рассматривает такие возможности, как подсчет ссылок некоторых типов, а не других ( IRefCounted !), Или подсчет ссылок конкретных экземпляров, и почему ни одно из этих решений не было признано приемлемым.

Потому что [проблема с ресурс управление и детерминированный завершение] такое деликатная тема, я постараюсь быть максимально точным и полным в моем объяснение, как могу. прошу прощения за длина почты. Первые 90% этого письма пытается убедить вас что проблема действительно сложная. В в последней части я расскажу о вещах мы пытаемся сделать, но вам нужно первая часть, чтобы понять, почему мы рассматривая эти варианты.

...

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

...

Вкратце:

  • Мы считаем, что очень важно решить проблему цикла не заставляя программистов понимать, отслеживать и проектировать вокруг этой сложной структуры данных проблемы.
  • Мы хотим убедиться, что у нас высокая производительность (как скорость, так и рабочий набор) и наш анализ показывает, что при использовании подсчета ссылок для каждого отдельного объекта в системе не позволит нам добиться этого цель .
  • По разным причинам, включая состав и состав вопросов нет простого прозрачного решение иметь только эти объекты которые необходимо учитывать .
  • Мы решили не выбирать решение, которое обеспечивает детерминированный доработка сингла язык / контекст, потому что он препятствует взаимодействовать с другими языками и вызывает бифуркацию библиотек классов путем создания специфичных для языка версии.
49
ответ дан 26 November 2019 в 17:46
поделиться

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

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

Подсчет ссылок не собирает циклы. Подсчет ссылок также имеет меньшую пропускную способность (в целом медленнее), но с преимуществом более быстрых пауз (максимальные паузы меньше), чем сборщик трассировки.

5
ответ дан 26 November 2019 в 17:46
поделиться

Сборщик мусора не требует, чтобы вы писали метод Dispose для каждого класса / типа, который вы определяете. Вы определяете только один, когда вам нужно явно что-то сделать для очистки; когда вы явно выделили собственные ресурсы. В большинстве случаев сборщик мусора просто освобождает память, даже если вы выполняете только что-то вроде new () для объекта.

Сборщик мусора выполняет подсчет ссылок - однако он делает это по-другому, определяя, какие объекты «достижимы» ( Ref Count> 0 ) каждый раз, когда он выполняет сбор ... он просто не выполняет это целочисленным счетчиком. , Собираются недостижимые объекты ( Ref Count = 0 ). Таким образом, среда выполнения не должна выполнять обслуживание / обновление таблиц каждый раз, когда объект назначается или освобождается ... должен быть быстрее.

Единственное существенное различие между C ++ (детерминированным) и C # (недетерминированным) заключается в том, что объект будет очищен. Вы не можете предсказать точный момент, когда объект будет собран в C #.

Пятнадцатый плагин: я бы рекомендовал прочитать стандартную главу Джеффри Рихтера о GC в CLR через C # , если вам действительно интересно, как работает GC.

31
ответ дан 26 November 2019 в 17:46
поделиться

В C # была произведена попытка подсчета ссылок. Я считаю, что люди, выпустившие Rotor (эталонная реализация CLR, для которой был предоставлен исходный код), ссылались на сборку мусора на основе подсчета, чтобы посмотреть, как он будет сравниваться с поколениями. Результат был удивительным - "стоковая" GC была настолько быстрее, что даже не смешно. Я не помню точно, где я это слышал, думаю, это был один из подкастов Hanselmuntes. Если вы хотите увидеть, как C ++ проигрывает по производительности по сравнению с C # - используйте приложение китайского словаря Раймонда Чена в Google. Он сделал версию на C ++, а затем Рико Мариани сделал версию на C #. Я думаю, что Рэймонду потребовалось 6 итераций, чтобы наконец превзойти версию C #, но к тому времени ему пришлось отказаться от всех хороших объектно-ориентированных функций C ++ и перейти к уровню API Win32. Все это превратилось в хакерство производительности. Программа на C # при этом была оптимизирована только один раз и в итоге все еще выглядела как достойный объектно-ориентированный проект

23
ответ дан 26 November 2019 в 17:46
поделиться

Здесь много проблем. Прежде всего, вам нужно различать между освобождением управляемой памяти и очисткой других ресурсов. Первый может быть очень быстрым, тогда как второй может быть очень медленным. В .NET они разделены, что позволяет ускорить очистку управляемой памяти. Это также подразумевает, что вы должны реализовывать Dispose / Finalizer только тогда, когда вам нужно очистить что-то помимо управляемой памяти.

.NET использует метод отметки и очистки, когда он просматривает кучу в поисках корней объектов. Укоренившиеся экземпляры выживают при сборке мусора. Все остальное можно очистить, просто восстановив память. Сборщику мусора время от времени приходится сжимать память, но, помимо этого, восстановление памяти - это простая операция с указателем, даже при восстановлении нескольких экземпляров. Сравните это с несколькими вызовами деструкторов в C ++.

что вы должны реализовывать Dispose / Finalizer только тогда, когда вам нужно очистить что-то помимо управляемой памяти.

.NET использует метод отметки и очистки, когда он просматривает кучу в поисках корней к объектам. Укоренившиеся экземпляры выживают при сборке мусора. Все остальное можно очистить, просто восстановив память. Сборщику мусора время от времени приходится сжимать память, но, помимо этого, восстановление памяти - это простая операция с указателем, даже при восстановлении нескольких экземпляров. Сравните это с несколькими вызовами деструкторов в C ++.

что вы должны реализовывать Dispose / Finalizer только тогда, когда вам нужно очистить что-то помимо управляемой памяти.

.NET использует метод отметки и очистки, когда он просматривает кучу в поисках корней к объектам. Укоренившиеся экземпляры выживают при сборке мусора. Все остальное можно очистить, просто восстановив память. Сборщику мусора время от времени приходится сжимать память, но, помимо этого, восстановление памяти - это простая операция с указателем, даже при восстановлении нескольких экземпляров. Сравните это с несколькими вызовами деструкторов в C ++.

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

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

4
ответ дан 26 November 2019 в 17:46
поделиться

Объект, реализующий IDisposable, должен также реализовывать финализатор, вызываемый сборщиком мусора, когда пользователь явно не вызывает Dispose - см. IDisposable.Dispose в MSDN .

Вся суть IDisposable в том, что сборщик мусора работает в некое недетерминированное время, а вы реализуете IDisposable, потому что у вас есть ценный ресурс и вы хотите освободить его в детерминированное время.

Таким образом, ваше предложение ничего не изменит в условия IDisposable.

Изменить:

Извините. Неправильно прочитал ваше предложение. : - (

В Википедии есть простое объяснение недостатков подсчитываемых ссылок GC

1
ответ дан 26 November 2019 в 17:46
поделиться

Счетчик ссылок

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

Сборка мусора в .NET

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

В дополнение к вышесказанному GC использует концепцию поколений для более эффективной сборки мусора. В его основе лежат следующие концепции 1. Быстрее сжать память для части управляемой кучи, чем для всей управляемой кучи. 2. У новых объектов будет более короткий срок жизни, а у более старых объектов - более длительный. 3. Новые объекты, как правило, связаны друг с другом, и приложение обращается к ним примерно в одно и то же время

. Управляемая куча разделена на три поколения: 0, 1 и 2. Новые объекты хранятся в поколении 0. Объекты, которые не восстанавливаются циклом сборки мусора, переходят к следующему поколению. Таким образом, если новые объекты, которые находятся в поколении 0, выживают в цикле GC 1, то они повышаются до поколения 1. Те ​​из них, которые пережили цикл GC 2, повышаются до поколения 2. Поскольку сборщик мусора поддерживает только три поколения, объекты в поколении 2, которые выжить в коллекции остаются в поколении 2 до тех пор, пока они не будут определены как недоступные в будущей коллекции.

Сборщик мусора выполняет сборку, когда поколение 0 заполнено, и необходимо выделить память для нового объекта. Если коллекция поколения 0 не восстанавливает достаточно памяти,

1
ответ дан 26 November 2019 в 17:46
поделиться

Существует разница между подсчетом ссылок интеллектуального указателя в стиле C ++ и сборкой мусора с подсчетом ссылок. Я также говорил о различиях в моем блоге , но вот краткое изложение:

Подсчет ссылок на стиль C ++:

  • Неограниченные затраты на декремент: если корень большой структуры данных уменьшается до нуля, возникает неограниченная стоимость для освобождения всех данных.

  • Ручной сбор цикла: , чтобы предотвратить утечку памяти из циклических структур данных, программист должен вручную сломать любые потенциальные структуры, заменив часть цикла слабым интеллектуальным указателем. Это еще один источник потенциальных дефектов.

Сборка мусора с подсчетом ссылок

  • Отложенный RC: Изменения счетчика ссылок на объект игнорируются для ссылок на стек и регистр. Вместо этого, когда запускается сборщик мусора, эти объекты сохраняются путем сбора корневого набора. Изменения в счетчике ссылок можно отложить и обрабатывать пакетами. Это приводит к более высокой пропускной способности .

  • Объединение: с использованием барьера записи можно объединить изменения в счетчике ссылок. Это позволяет игнорировать большинство изменений в счетчике ссылок на объекты, улучшая производительность RC для часто изменяемых ссылок.

  • Обнаружение цикла: для полной реализации GC также должен использоваться детектор цикла. Однако можно выполнять обнаружение цикла инкрементным способом, что, в свою очередь, означает ограниченное время сборки мусора.

В принципе, можно реализовать высокопроизводительный сборщик мусора на основе RC для таких сред выполнения, как JVM Java и среда выполнения CLR .net.

128] Я думаю, что сборщики трассировки частично используются по историческим причинам: многие из недавних улучшений в подсчете ссылок произошли после того, как были выпущены как JVM, так и среда выполнения .net. Исследовательская работа также требует времени для перехода в производственные проекты.

Детерминированное использование ресурсов

Это отдельный вопрос. Среда выполнения .net делает это возможным с помощью интерфейса IDisposable, как показано ниже. Мне также нравится ответ Гишу .


@Skrymsli , это цель ключевого слова « using ». Например:

public abstract class BaseCriticalResource : IDiposable {
    ~ BaseCriticalResource () {
        Dispose(false);
    }

    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this); // No need to call finalizer now
    }

    protected virtual void Dispose(bool disposing) { }
}

Затем добавить класс с критическим ресурсом:

public class ComFileCritical : BaseCriticalResource {

    private IntPtr nativeResource;

    protected override Dispose(bool disposing) {
        // free native resources if there are any.
        if (nativeResource != IntPtr.Zero) {
            ComCallToFreeUnmangedPointer(nativeResource);
            nativeResource = IntPtr.Zero;
        }
    }
}

Затем использовать его так же просто, как:

using (ComFileCritical fileResource = new ComFileCritical()) {
    // Some actions on fileResource
}

// fileResource's critical resources freed at this point

См. Также правильную реализацию IDisposable .

14
ответ дан 26 November 2019 в 17:46
поделиться
Другие вопросы по тегам:

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