Слабая ссылка на IDisposable - PullRequest
0 голосов
/ 28 марта 2019

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

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

Справочная информация: У нас есть приложение WinForms с контроллером, хранящим данные. Несколько элементов управления пользовательского интерфейса могут представлять данные в любой момент времени. Форма добавляет и удаляет элементы управления (и вызывает Dispose, когда удаляет их), но не знает, что делают элементы управления и какие данные им нужны. Ранее элементы управления подписывались на события от контроллера для получения уведомлений при обновлении данных. Это приводит к утечкам памяти. Чтобы устранить эту проблему, контроллер теперь сохраняет слабые ссылки на элементы управления и уведомляет о тех, которые еще живы.

Ответы [ 2 ]

2 голосов
/ 28 марта 2019

Поскольку IDisposable и WeakReference имеют взаимоисключающую семантику, вам нужно выбрать одну. Объединять их опасно, так как после удаления объект, скорее всего, будет иметь несовместимое состояние, которое не подходит для повторного использования. IDisposable подразумевает, что вы хотели бы контролировать жизненный цикл ваших объектов и не собираетесь забирать их обратно. Это все равно что положить что-то в мусорный контейнер и сказать: «Я покончил с этим, теперь мне все равно, что будет с этим». Семантика WeakReference похожа на то, чтобы положить что-то рядом с мусорным контейнером и сказать: «Я вернусь через 30 минут или около того, если никто не положит это в этот мусорный контейнер, я возьму это обратно, но если оно внутри, я не не волнует ".

Слабые ссылки подразумевают, что объекты, на которые они ссылаются, не имеют долгой жизни, что они хороши для быстрого восстановления памяти, но в то же время они дают некоторый шанс для повторного использования, так что в вашем случае вы можете положиться исключительно на WeakReference<T>:

MyType instance;
if (weakRef.TryGetTarget(out instance))
{
    // resurrected, still can use it
}
else
{
   // object is collected, the new one should be created
}
0 голосов
/ 10 апреля 2019

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

public void OnDataChanged(object model)
{
    if (IsDisposed)
    {
        return;
    }
    ...
    // method implementation
}

Это было необходимо только в случае вызова одной функции из слабой ссылки.

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

...