2016-07-23 3 views
5

. NET MemoryCache - это кеш объектов C#. Некоторые объекты могут иметь сложную структуру, а другие могут иметь небезопасные ссылки. Является ли C# делать магию для реализации PhysicalMemoryLimit или просто вычисляет мелкий размер каждого объекта?.NET MemoryCache: как это ограничивает ограничение памяти?

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

+0

Я уверен, что кэш пытается вычислить размер объектов в кеше. Было бы бесполезно это делать, поскольку (а) размер произвольного объекта может измениться после его вставки в кеш и (б) могут быть другие ссылки на объекты, на которые ссылаются поля кэшированного объекта, так что удаление из кеша не обязательно освобождает всю память. – Joe

+1

Независимо от того, что он делает, он реализуется с помощью этого метода: http://referencesource.microsoft.com/#mscorlib/system/gc.cs,6da6dff768f373f5 – fernacolo

+0

Изменен контент вопроса. –

ответ

7

.NET MemoryCache похож на класс ASP.NET Cache. Если мы посмотрим на кеш ASP.NET, мы увидим функцию CacheItemRemovedCallback. Это срабатывает, когда элемент удаляется из кэша.

Эта функция дает CacheItemRemovedReason с функцией обратного вызова. Если мы рассмотрим причины, мы увидим, что элемент можно удалить из кеша, потому что система удалила его в свободную память. Таким образом, в то время как PhysicalMemoryLimit дает процент физической памяти, который кеш может использовать в одном проходе, я думаю, что они оставят его системе, чтобы очистить кеш, если он достигнет предела.

Если вы действительно положили элемент кэша в кеш с помощью функции Add, он добавит его в качестве нового экземпляра CacheItem. Поэтому он будет учитываться несколько раз. Если вы используете функцию AddOrGetExisting, она проверяет, все ли элементы в кеше. Если это так, он будет использовать этот экземпляр, а не новый экземпляр. Таким образом, он будет учитываться один раз.

Надеюсь, это поможет вам в правильном направлении.

+0

Я не уверен, что это так. Измерение выполняется на всем MemoryCache: http://referencesource.microsoft.com/#System.Runtime.Caching/System/Caching/CacheMemoryMonitor.cs,54. Таким образом, он может рассчитывать дублированный объект только один раз. – fernacolo

+0

Вы также не рассматриваете сценарии, в которых AddOrGetExisting используется с разными ключами, но с одним и тем же экземпляром значения. Рассчитывается ли это значение один или несколько раз? – fernacolo

1

Вот источник. Ответ на ваш второй вопрос очевиден, если вы посмотрите на реализацию метода Add: referencesource.microsoft.com, вызывающий AddOrGetExisting.

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

+0

Этот источник ничего не отвечает. Пользователь может поместить один и тот же объект несколько типов в кеш, под разными ключами. MemoryCache не проверяет, добавлено ли значение. Он проверяет, только если ключ уже добавлен, а для кеширования значение обычно занимает больше места. Плюс, этот код фактически не подсчитывает размер и не принимает решения об исключении предметов для соблюдения ограничений памяти. – fernacolo

+0

Не в этом дело (по крайней мере, насколько я понимаю). Для целей кеша сам объект не имеет значения. Важно только ключевое. И это разумно, потому что есть те же объекты, которые можно использовать по всей системе несколько раз, и их нужно хранить отдельно, потому что ключ - это то, что описывает цель объекта в этом механизме. –

+0

Также есть вызовы неуправляемого кода для получения текущего использования памяти: 'if (UnsafeNativeMethods.GlobalMemoryStatusEx (ref memoryStatusEx)! = 0) { s_totalPhysical = memoryStatusEx.ullTotalPhys; s_totalVirtual = memoryStatusEx.ullTotalVirtual; } ' , который затем используется при расчете давления ' if (memory> = 0x100000000) { _pressureHigh = 99; } else if (memory> = 0x80000000) { _pressureHigh = 98; } ' Возможно, я пропустил вашу мысль, но в источниках есть много ответов. –

-2

Вы не можете легко установить PhysicalMemoryLimit или членов CacheMemoryLimit класса MemoryCache, поскольку они не имеют сеттеры реализованы (по крайней мере в версии .Net 4.0).

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

+1

Документы .NET 4, похоже, предлагают иначе: https://msdn.microsoft.com/en-us/library/system.runtime.caching.configuration.memorycacheelement(v=vs.100).aspx. В частности, ['CacheMemoryLimitMegabytes'] (https://msdn.microsoft.com/en-us/library/system.runtime.caching.configuration.memorycacheelement.cachememorylimitmegabytes (v = vs.100) .aspx). –

2

Чтение документации, похоже, что кеш не пытается вычислить размер объектов, которые он кэширует. Это имеет смысл, потому что это не то, что может быть сделано из самого процесса для произвольных типов (вы можете сделать это для структур фиксированного размера или массивов структур фиксированного размера, но это о нем); немного поискового запроса подтвердит это вам. Однако он знает, сколько оперативной памяти доступно на компьютере; вы можете получить это от new Microsoft.VisualBasic.Devices.ComputerInfo().AvailablePhysicalMemory. Таким образом, предположительно кеш выполняет две вещи:

  1. Он отслеживает, когда последний раз использовался последний объект.
  2. Опросы для статистики памяти с некоторым интервалом.

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

Если вы думаете об этом, это почти все, что вы можете сделать с информацией, доступной в кеше.

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

+0

Если вы посмотрите исходный код, вы увидите, что он фактически получает размер объектов в кеше. Он использует специальный указатель, который инструктирует сборщик мусора оценить размер графа объекта в течение его цикла сбора. Документация для MemoryCache сильно отсутствует. Например, этот метод подсчета памяти подразумевает, что элементы кэша должны быть достаточно автономными без ссылок на «родительские» объекты, и в противном случае размер графа объекта совершенно бесполезен. –

+0

Интересно, спасибо. – briantyler

Смежные вопросы