2016-07-23 4 views
5

.NET MemoryCacheは、C#オブジェクトのキャッシュです。複雑な構造を持つオブジェクトもあれば、安全でない参照を持つ可能性のあるオブジェクトもあります。 C#はPhysicalMemoryLimitを実装するためのいくつかの魔法をしているのですか、それとも各オブジェクトの浅いサイズを計算しているだけですか?.NET MemoryCache:メモリ制限をどのように適用しますか?

私は後でそうだと思う。それでも、キャッシュ内に同じオブジェクトを複数回置いた場合(欠落したアイテムを追跡する場合など)、そのサイズは1回だけ、またはそのインスタンスを含む各エントリについて考慮されますか?

+0

私は、キャッシュがキャッシュ内のオブジェクトのサイズを計算しようとすることができます確信しています。 (a)任意のオブジェクトのサイズがキャッシュに挿入された後に変更される可能性があり、(b)キャッシュされたオブジェクトのフィールドによって参照されるオブジェクトへの他の参照が存在する可能性があるので、そうすることは無益である。キャッシュから取り除いても必ずしもすべてのメモリが解放されるわけではありません。 – Joe

+1

はそれがないものは何でも、それはこの方法で実装されています:http://referencesource.microsoft.com/#mscorlib/system/gc.cs,6da6dff768f373f5 – fernacolo

+0

は、質問の内容を変更しました。 –

答えて

7

.NET MemoryCacheは、ASP.NET Cacheクラスに似ています。 ASP.NETキャッシュを見ると、CacheItemRemovedCallbackという関数があります。これは、アイテムがキャッシュから削除されたときに起動されます。

この関数は、コールバック関数を持つCacheItemRemovedReasonを返します。理由を調べると、システムがメモリを解放するためにアイテムがキャッシュから削除される可能性があることがわかります。したがって、PhysicalMemoryLimitは、キャッシュが1つのトレッドで使用できる物理メモリの割合を示していますが、限界に達するとキャッシュをクリアするためにシステムに残すと思います。

実際にキャッシュ項目をAdd関数を使用してキャッシュに入れると、それを新しいCacheItemインスタンスとして追加します。だから、それは何回も説明されるでしょう。 AddOrGetExistingファンクションを使用すると、アイテムがキャッシュ内にすべて存在するかどうかがチェックされます。そうであれば、そのインスタンスを使用し、新しいインスタンスは使用しません。それで、それは一度説明されます。

これは正しい方向に役立ちます。

+0

これが本当かどうかわかりません。測定はMemoryCache全体で実行されます:http://referencesource.microsoft.com/#System.Runtime.Caching/System/Caching/CacheMemoryMonitor.cs,54。したがって、重複したオブジェクトは1回だけ数えられます。 – fernacolo

+0

AddOrGetExistingが異なるキーで同じ値のインスタンスで使用されるシナリオも考慮していません。その値は1回または複数回カウントされますか? – fernacolo

1

ここにソースがあります。あなたの2番目の質問への答えはAddメソッドの実装を見れば明らかです:referencesource.microsoft.com AddOrGetExistingを呼び出しています。

サイズについてはわかりませんが、魔法はまったくないと仮定していると思います。また興味がある場合は、ソースを詳細に調べることができます。

+0

そのソースは何も答えません。ユーザーは、同じオブジェクトを複数のタイプのキャッシュに異なるキーで配置できます。 MemoryCacheは、値がすでに追加されているかどうかをチェックしません。これは、キーがすでに追加されているかどうかだけをチェックし、キャッシングの目的のためには、通常、より多くのスペースが必要です。 さらに、そのコードは実際にはサイズを数えずに、メモリ制限を尊重するためにアイテムを追い出すという決心をしていません。 – fernacolo

+0

それはポイントではありません(少なくとも私がそれを理解するように)。キャッシュ目的のために、オブジェクト自体は重要ではない。キーだけが重要です。また、システム全体で複数回使用できる同じオブジェクトがあり、別々に格納する必要があるため、合理的です。なぜなら、このメカニズムではオブジェクトの目的を説明するキーが重要なためです。 –

+0

また、現在のメモリ使用量を取得するためのアンマネージコードの呼び出しがあります。 'if(UnsafeNativeMethods.GlobalMemoryStatusEx(ref memoryStatusEx)!= 0){ s_totalPhysical = memoryStatusEx.ullTotalPhys; s_totalVirtual = memoryStatusEx.ullTotalVirtual; }後圧力 を計算しながら、利用される '' 場合(メモリ> = 0x100000000){ _pressureHigh = 99。 }そうであれば(メモリ> = 0×80000000){ _pressureHigh = 98。 } ' 私はあなたの意見を忘れていたかもしれませんが、情報源にはたくさんの回答があります。 –

-2

MemoryCacheクラスのPhysicalMemoryLimitメンバーまたはCacheMemoryLimitメンバーは、少なくとも.Net 4.0バージョンではが実装されていないため、簡単に設定できません。

オブジェクトの1つのインスタンスだけがキャッシュされるようにするには、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

ドキュメントを読むと、キャッシュはキャッシュしているオブジェクトのサイズを計算しようとしません。これは、プロセス自体から任意の型(固定サイズの構造体、または固定サイズの構造体の配列に対して行うことはできますが、それについてはそれを行うことができます)では実行できないものなので意味があります。グーグルのビットがあなたにそれを確認します。しかし、どのくらいのRAMがコンピュータ上で利用可能であるかはわかります。あなたはnew Microsoft.VisualBasic.Devices.ComputerInfo().AvailablePhysicalMemoryからあなた自身を得ることができます。したがって、おそらくキャッシュは2つのことを行います:

  1. 各オブジェクトが最後に使用されたときに追跡されます。
  2. 一定の間隔でメモリ統計をポーリングします。

次に、各ポーリングで、使用可能なメモリの量が許容範囲内にあるか、そうでないかのいずれかです。それが許容範囲内であれば、何もしません。そうでない場合は、項目の削除が開始され、最後に最後にアクセスされた項目が最初に削除されます。メモリが許容範囲内に戻るまでアイテムを削除し続けます。あなたが考えてみれば

はそれはかなりあなたがキャッシュに利用可能な情報を使用して実行できるすべてです。

この戦略はOKですが、キャッシュから項目を削除すると、ガベージコレクションのためにそれを解放しませんので、キャッシュ内の項目への参照を保持している他のオブジェクトを持っている場合、それは明らかに分解します。これは、オブジェクトへの参照がなくなるようにクリーンアップを実行するコールバックのポイントです。

+0

ソースコードを調べると、キャッシュ内のオブジェクトのサイズが実際に取得されることがわかります。それはガベージコレクタに、収集サイクル中のオブジェクトグラフサイズを推定するよう指示する特別なポインタを使用します。 MemoryCacheのドキュメントはひどく欠けています。例えば、このメモリ計数方法は、キャッシュアイテムが「親」オブジェクトへの参照なしでかなり自己完結型でなければならないことを意味し、そうでなければオブジェクトグラフサイズは全く役に立たない。 –

+0

面白い、ありがとう。 – briantyler

関連する問題