Как получить уведомление, если объект собирается мусором? - PullRequest
2 голосов
/ 10 января 2012

Короткая версия:

Для класса кеша мне нужно получать уведомление, если объект собирает мусор (чтобы удалить соответствующие записи из моего кеша).Каков наилучший способ сделать это?Отправка события из деструктора?

Длинная версия:

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

double myFunc(HugeParTree parTree, int dynPar1, double dynPar2)

Я хочу кэшировать эти функции следующим образом:

  • Кэшировать результаты для кортежей (parTree.GUID, dynPar1, dynPar2, ...)
  • Когда parTree изменяется, что случается редко, все соответствующие записи в кэше удаляются (через шаблон Observer).(parTree.Equals() слишком дорого; сравнивает более 100 типов значений).

Код выглядит прямо сейчас (для одного параметра значения):

public class CachedFunction1ObsPar1Par<TRet, TObsPar1, TPar1>
        where TObsPar1 : IObservable, IProvideGUID
    {
        public delegate TRet ValueCalculator(TObsPar1 obsPar1, TPar1 par1);

        public CachedFunction1ObsPar1Par(ValueCalculator calc)
        {
            _calc = calc;
        }


        #region members

        private ValueCalculator _calc;

        private Dictionary<Guid, Dictionary<TPar1, TRet>> _cache = 
            new Dictionary<Guid, Dictionary<TPar1,TRet>>();

        #endregion


        public TRet value(TObsPar1 obsPar1, TPar1 par1)
        {
            TRet result;
            bool cacheHit = checkCache(obsPar1, par1, out result);

            if (cacheHit)
            {
                Debug.Assert(result.Equals(_calc(obsPar1, par1)));
                return result;
            }
            else
            {
                result = _calc(obsPar1, par1);
                _cache[obsPar1.GUID].Add(par1, result);
                return result;
            }
        }

        private bool checkCache(TObsPar1 obsPar1, TPar1 par1, out TRet result)
        {
            if (!_cache.ContainsKey(obsPar1.GUID))
            {
                _cache.Add(obsPar1.GUID, new Dictionary<TPar1, TRet>());
                obsPar1._changed += this.invalidateCache;
            }

            Dictionary<TPar1, TRet> guidCache = _cache[obsPar1.GUID];

            bool success = guidCache.TryGetValue(par1, out result);

            return success;
        }

        private void invalidateCache(object sender)
        {
            TObsPar1 obsPar = (TObsPar1)sender;

            _cache.Remove(obsPar.GUID);

            obsPar._changed -= this.invalidateCache;
        }
    }

У меня естьеще не проверил это, так как у меня все еще есть проблема, что записи в кэше никогда не удаляются после того, как соответствующее parTree больше не используется.Мне бы хотелось синхронное решение без повторных «проверок» для очень старых записей в кэше.

Ответы [ 3 ]

8 голосов
/ 10 января 2012

Для класса кэша мне нужно получать уведомление, если объект является мусором собрал (чтобы удалить соответствующие записи из моего кэша). Что лучший способ сделать это? Отправка события из деструктора?

Если ваш кеш содержит нормальные (сильные) ссылки, элементы никогда не будут собраны.

Если ваш кеш содержит WeakReferences, вам не нужно ничего удалять.

1 голос
/ 10 января 2012

Хенк уже упомянул недостаток в вашем требовании.

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

~YourClass();

Согласно MSDN:

Этот метод автоматически вызывается после того, как объект становится недоступным

Хотя никогда не рекомендуется полагаться на ГХ илидеструктор.

1 голос
/ 10 января 2012

Вы можете определить интерфейс 'ICacheable', который должен быть реализован объектами в кэше.В методе интерфейса RemoveFromCache() вы можете искать в кеше его дочерние объекты и удалять их.

Когда вы удаляете элемент из кэша, протестируйте его для интерфейса и вызывайте RemoveFromCache().

Это похоже на IDisposable.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...