C #: Уведомление перед сбором WeakReference? - PullRequest
9 голосов
/ 18 июля 2009

В C # /. NET есть ли способ получить уведомление, прежде чем объект, на который указывает слабая ссылка, будет уничтожен? По сути, я хочу разрешить сбор объекта, но сделать что-то прямо перед его уничтожением, не изменяя код для добавления деструкторов (поскольку я не буду точно знать, какие типы объектов будут использоваться в моем коде).

Спасибо, Роберт

Ответы [ 6 ]

7 голосов
/ 04 июня 2012

.Net 4.0 имеет необходимое решение: ConditionalWeakTable . Вот короткая программа, которая демонстрирует идею. (здесь обсуждается )

using System;
using System.Runtime.CompilerServices;

namespace GCCollectNotification
{
    class ObjectToWatch { }

    class Notifier
    {
        public object ObjectToWatch { get; set; }
        ~Notifier() { Console.WriteLine("object is collected"); }
    }

    class Program
    {
        private ConditionalWeakTable<object, Notifier> map
            = new ConditionalWeakTable<object, Notifier>();

        public void Test()
        {
            var obj = new ObjectToWatch();
            var notifier = map.GetOrCreateValue(obj);
            notifier.ObjectToWatch = obj;
        }

        static void Main(string[] args)
        {
            new Program().Test();

            GC.Collect();
            GC.WaitForPendingFinalizers();

            // "object is collected" should have been printed by now

            Console.WriteLine("end of program");
        }
    }
}
6 голосов
/ 18 июля 2009

Вы не можете этого сделать. Однако вы можете наблюдать за приближением GC (в CLR v3.5Sp1 есть новые API GC, которые позволяют вам делать это, GCNotifications)

6 голосов
/ 18 июля 2009

Нет, нет способа достичь этой функциональности.

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

Учтите, что в тот момент, когда объект, содержащийся в WeakReference, собран, ссылок больше нет (следовательно, его можно собрать). Чтобы какое-либо событие вам пригодилось, необходимо предоставить объект как часть события. Это означает, что ссылка превратилась из коллекционной в не подлежащую Ничто не мешает коду обработки получить ссылку на этот объект. Следовательно, объект больше нельзя считать коллекционным. CLR нужно будет сделать второй проход на объекте, чтобы убедиться, что его можно было собрать.

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

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

0 голосов
/ 18 ноября 2010

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

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

К сожалению, я не видел полных реализаций такой стратегии. Есть несколько важных предостережений для рассмотрения. Среди них: (1) финализаторы никогда не должны ждать блокировок и не делать ничего, что могло бы вызвать исключение; (2) код, который обращается к другим объектам, которые могли выйти за пределы области видимости, должен быть подготовлен для того, чтобы они могли быть уже завершены, находились в процессе завершения, ожидали завершения или все еще имели живые ссылки в других местах; (3) если финализатор хранит корневую ссылку на финализируемом объекте, который был признан пригодным для сбора мусора, такой объект может быть завершен, даже если существует живая ссылка.

0 голосов
/ 04 августа 2009

Для того, что вы описываете, финализаторы были бы лучшим подходом.

0 голосов
/ 18 июля 2009

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

Какую проблему с дизайном вы хотите решить? Там может быть лучший способ.

...