确切地说,MemoryCache的内存限制是什么意思?

Joe*_*nta 6 .net c# caching memorycache

System.Runtime.Caching.MemoryCache是.NET Framework(版本4+)中的一个类,它使用字符串作为键来缓存内存中的对象.除了System.Collections.Generic.Dictionary <string,object>之外,这个类还有各种各样的铃声和口哨声,可以让你配置缓存增长到多少(绝对或相对术语),设置不同的过期策略不同的缓存项目,以及更多.

我的问题与记忆限制有关.MSDN上的所有文档似乎都没有令人满意地解释这一点,并且Reference Source上的代码相当不透明.很抱歉将所有这些都写成一个"问题",但我无法弄清楚如何将一些问题纳入他们自己的问题,因为他们只是对一个整体问题的不同观点:"你如何调和惯用的C# /.NET有一个通常有用的内存缓存的概念,它有可配置的内存限制几乎完全在托管代码中实现?"

  1. 密钥大小是否计入MemoryCache占用的空间?实习池中的键怎么样,每个键应该只添加对象引用的大小到缓存的大小?
  2. 在确定池中存储的对象的大小时,MemoryCache是​​否考虑的不仅仅是它存储的对象引用的大小? 我的意思是......它必须,对吗?否则,配置选项对于常见情况极具误导性......对于其余问题,我将假设它确实如此.
  3. 鉴于MemoryCache几乎肯定会考虑超过缓存中存储的值的对象引用的大小,它有多深?
    1. 如果我实现这样的事情,我会觉得困难的考虑单个对象的"子"成员的内存使用情况,也没有拉动"父"的参考性.
    2. 例如,想象一下游戏应用程序中的一个类,Player. Player有一些特定于玩家的状态被封装在一个public PlayerStateData PlayerState { get; }属性中,该属性封装了玩家正在看的方向,他们持有的链轮数等等,以及对整个游戏状态的引用public GameStateData GameState { get; },可以用来回到游戏(更大)状态来自只知道玩家的方法.
    3. MemoryCache是​​否考虑两者PlayerState以及GameState何时考虑缓存贡献的大小?
    4. 也许它更像是" 直接存储在缓存中的对象所占用的托管堆上的大小,以及通过这些对象的成员可以访问的所有东西"?
    5. GameState仅仅因为5个玩家被缓存而将大小的贡献大小乘以5 是愚蠢的......但是再一次,一个可能的实现可能就是这样,并且很难计算PlayerState而不计算GameState.
  4. 如果一个对象在MemoryCache中多次存储,那么每个条目是否分别计入限制?
  5. 与前一个相关,如果一个对象直接存储在MemoryCache中,而且间接存储在另一个对象的成员中,那么它们对内存限制有什么影响?
  6. 如果一个对象存储在MemoryCache中,但也被一些完全与MemoryCache断开连接的其他活动对象引用,哪些对象计入内存限制?如果它是一个对象数组,有些(但不是全部)有传入的外部引用呢?

我自己的研究使我SRef.cs,我放弃了在试图让后了解这里,后来导致这里.猜测所有这些问题的答案将围绕寻找和冥想最终填充存储在该句柄中的INT64的代码.

Mik*_*ski 1

我知道这已经晚了,但我已经对源代码进行了大量挖掘,试图了解发生了什么,现在我有了一个相当好的想法。我想说,MemoryCache 是 MSDN 上记录最差的类,这让我对那些试图优化应用程序的人使用的东西感到困惑。

MemoryCache 使用特殊的“大小引用”来测量对象的大小。这一切看起来像是内存缓存源代码中的一个巨大的黑客攻击,涉及反射来包装一个名为“System.SizedReference”的内部类型,据我所知,这会导致 GC 在第 2 代期间设置它指向的对象图的大小收藏。

根据我的测试,这将包括父对象的大小,以及父对象引用的所有子对象等,但我发现,如果您对父对象弱引用进行引用(即通过WeakReferenceWeakReference<>),那么它不再被计算在内作为对象图的一部分,这就是我现在对所有缓存对象所做的事情。

我认为缓存对象需要完全独立,或者使用对其他对象的弱引用才能使内存限制发挥作用。

如果您想自己使用它,只需复制 中的代码SRef.cs,创建一个对象图并将一个新的 SRef 实例指向它,然后调用 GC.Collect。收集后,近似大小将设置为对象图的大小。