Использование воскресения объекта - PullRequest
14 голосов
/ 10 сентября 2010

У меня проблема с утечками памяти в приложении-службе Windows .NET.Поэтому я начал читать статьи об управлении памятью в .NET.И я нашел интересную практику в одной из статей Джеффри Рихтера .Эта практика называется «Воскресение объекта».Это похоже на ситуационный код, который инициализирует глобальную или статическую переменную «this»:

protected override void Finalize() {
     Application.ObjHolder = this;
     GC.ReRegisterForFinalize(this);
}

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

Ответы [ 5 ]

7 голосов
/ 10 сентября 2010

Из той же статьи: «Воскресения очень мало, и вам действительно следует избегать его, если это возможно».

Лучшее использование, которое я могу придумать, - это шаблон «переработка».Рассмотрим Фабрику, которая производит дорогие, практически неизменные объекты;например, объекты, созданные путем анализа файла данных, или путем отражения сборки, или глубокого копирования графа «главного» объекта.Результаты вряд ли будут меняться каждый раз, когда вы выполняете этот дорогостоящий процесс.В ваших же интересах избегать создания экземпляров с нуля;однако по некоторым причинам проектирования система должна иметь возможность создавать множество экземпляров (без синглетонов), а ваши потребители не могут знать о Фабрике, чтобы они могли «вернуть» объект самостоятельно;им может быть вставлен объект, или ему может быть предоставлен делегат фабричного метода, из которого они получают ссылку.Когда зависимый класс выходит из области видимости, обычно это делает и экземпляр.

Возможный ответ - переопределить Finalize (), очистить любую изменяемую часть состояния экземпляра, а затем до тех пор, пока Factory будетв области, присоедините экземпляр к некоторому члену Фабрики.Это позволяет процессу сбора мусора, по сути, «перерабатывать» ценную часть этих объектов, когда в противном случае они выходили бы из области видимости и были бы полностью уничтожены.Фабрика может посмотреть и проверить, есть ли в мусорном контейнере какие-либо переработанные предметы, и если это так, она может отшлифовать ее и раздать.Фабрика должна будет создавать новую копию объекта только в том случае, если количество объектов, используемых процессом в целом, увеличилось.

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

В общем, если вы хотите, чтобы иждивенцы ДУМАЛИ, что они избавляются от объекта, или вам не нужно беспокоиться, но вы хотите сохранить экземплярВоскресение может быть хорошим инструментом, но вам придется ОЧЕНЬ внимательно его смотреть, чтобы избежать ситуаций, в которых объекты, получающие воскрешенные ссылки, становятся «упакованными крысами» и сохраняют каждый экземпляр, который когда-либо был создан в памяти, на протяжении всего жизненного цикла процесса.

5 голосов
/ 10 сентября 2010

Спекулятивный: в ситуации пула, такой как ConnectionPool.

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

4 голосов
/ 10 сентября 2010

Мой брат однажды работал на высокопроизводительной симуляционной платформе.Он рассказал мне, как в приложении построение объектов было очевидным узким местом для производительности приложения.Казалось бы, объекты были большими и требовали некоторой значительной обработки для инициализации.

Они реализовали репозиторий объектов для хранения «удаленных» экземпляров объектов.Перед созданием нового объекта они сначала проверяют, существует ли он уже в репозитории.

Компромисс был в увеличении потребления памяти (так как одновременно может существовать много неиспользуемых объектов) для повышения производительности (какобщее количество конструкций объектов было сокращено).

Обратите внимание, что решение о внедрении этого шаблона было основано на узких местах, которые они наблюдали в ходе профилирования в своем конкретном сценарии.Я ожидаю, что это будет исключительное обстоятельство.

3 голосов
/ 10 сентября 2010

Возможно, единственное место, где я могу использовать это, - это когда вы пытаетесь очистить ресурс, и очистка ресурса не удалась. Если было критически важно повторить процесс очистки, технически вы могли бы «Перерегистрировать» объект, который должен быть завершен, что, как мы надеемся, будет успешным, во второй раз.

При этом я бы на практике избегал этого.

1 голос
/ 10 августа 2014

Насколько я знаю, .net вызывает финализаторы в произвольном порядке. Если ваш класс содержит ссылки на другие объекты, они могли бы быть завершены (и, следовательно, удалены) при вызове вашего финализатора. Если вы затем решите воскресить ваш объект, у вас будут ссылки на завершенные / удаленные объекты.

class A {
  static Set<A> resurectedA = new Set<A>();
  B b = new B();
  ~A() {
    //will not die. keep a reference in resurectedA.
    resurectedA.Add(this);
    GC.ReRegisterForFinalize(this); 

    //at this point you may have a problem. By resurrecting this you are resurrecting b and b's Finalize may have already been called.
  } 
}
class B : IDisposable {
  //regular IDisposable/Destructor pattern http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx
}
...