2015-08-08 125 views
6

System.Runtime.Caching.MemoryCache是.NET Framework(版本4+)中的一個類,它使用字符串作爲鍵在內存中緩存對象。超過System.Collections.Generic.Dictionary<string, object>,這個類具有各種各樣的花裏胡哨的功能,可以讓您配置緩存可以增長多少(絕對或相對),爲不同的緩存項設置不同的過期策略等等。MemoryCache的內存限制意味着什麼?

我的問題與內存限制有關。 MSDN上的文檔似乎都不能令​​人滿意地解釋這一點,並且Reference Source上的代碼相當不透明。對不起,把所有這些都歸結爲一個「問題」,但我不知道如何解決他們自己的問題,因爲他們對於一個整體問題實際上只是不同的看法:「你如何調和慣用的C# /.NET與通常有用的內存緩存的概念有可配置的內存限制,幾乎完全在託管代碼中實現?「

  1. 密鑰大小是否計入MemoryCache被認爲佔用的空間?實習生池中的關鍵字是什麼?每個關鍵字只應該將對象引用的大小添加到緩存大小中?
  2. MemoryCache在確定存儲在池中的對象的大小時是否考慮的不僅僅是它存儲的對象引用的大小? 我的意思是...它必須,對吧?否則,配置選項對於常見情況是非常具有誤導性的......對於其餘問題,我將假定它確實如此。
  3. 鑑於MemoryCache幾乎肯定會考慮超過存儲在緩存中的值的對象引用的大小,它有多深?
    1. 如果我正在實施這樣的事情,我會覺得很很難考慮單個對象的「子」成員的內存使用情況,也沒有拉動「父」的參考性。
    2. 例如,想象一個遊戲應用中的課程,PlayerPlayer有一些玩家特定的狀態,封裝在public PlayerStateData PlayerState { get; }屬性中,該屬性封裝了玩家正在查看的方向,他們持有多少鏈輪等,以及對整個遊戲狀態public GameStateData GameState { get; }的引用,可用於獲取從只知道玩家的方法回到遊戲的(更大的)狀態。
    3. 在考慮對緩存的貢獻大小時,MemoryCache是​​否同時考慮PlayerStateGameState
    4. 也許它更像是「什麼是總共大小對直接存儲在緩存中的對象佔用的託管堆以及可通過這些對象的成員訪問的所有內容」?
    5. 似乎將GameState對限制的貢獻的大小乘以5僅僅是因爲有5個玩家被緩存會是愚蠢的......但是再一次,可能的實現可能會這樣做,並且很難計數不包括GameState
  4. 如果一個對象在MemoryCache中多次存儲,每個條目是否單獨計算到極限?
  5. 與上一個相關,如果一個對象直接存儲在MemoryCache中,但也通過另一個對象的成員間接存儲,那麼兩者對內存限制有什麼影響?
  6. 如果一個對象存儲在MemoryCache中,但也被一些其他活動對象引用完全與MemoryCache斷開連接,那麼哪些對象會計入內存限制?如果它是一個對象數組,一些(但不是全部)有傳入的外部引用?

我自己的研究使我SRef.cs,我放棄了在試圖獲得here,後來導致here後瞭解。猜測所有這些問題的答案將圍繞尋找並冥想最終填充存儲在該句柄中的INT64的代碼。

+0

IMO MemoryCache限制處理最有用的實現將涉及緩存能夠完美地回答問題,「如果我清除並且之後立即運行完整的GC,那麼在GC運行期間將釋放多少字節的內存?」但是我越想到這一點,如果緩存的所有者不遵守一些未公開的規則(或者至少是不可發現的規則),那麼我越希望它的回答會大幅度膨脹,所以這與更多理論的原因。 –

+0

我來這裏問完全相同的問題,特別是關於引用共享狀態。另一個問題也困擾着我......假設你的緩存對象(圖)放置在緩存中後會增長或縮小......?這一切都很模糊。 – spender

回答

1

我知道這已經晚了,但我已經在源代碼中進行了大量的挖掘,試圖瞭解發生了什麼,現在我有一個相當好的主意。我會說,MemoryCache是​​MSDN上記錄最差的類,這種困擾我的人試圖用來優化他們的應用程序。

MemoryCache使用特殊的「大小參考」來測量對象的大小。它看起來像是一個涉及反射的內存高速緩存源代碼中的一個巨大黑客,它包裝了一個名爲「System.SizedReference」的內部類型,從我可以知道的內容中導致GC設置它在第2代期間指向的對象圖的大小集合。

從我的測試,這將包括父對象的大小,因而深受家長等引用的所有子對象,但我發現,如果您對父對象的引用弱引用(即通過WeakReferenceWeakReference<>)那麼它不再被視爲對象圖的一部分,所以這就是我現在對所有緩存對象所做的事情。

我認爲緩存對象需要完全自包含或使用對其他對象的弱引用來限制內存限制。

如果你想自己玩,只需複製SRef.cs的代碼,創建一個對象圖並指向一個新的SRef實例,然後調用GC.Collect。收集之後,近似大小將被設置爲對象圖的大小。