2013年4月2日火曜日

.net framework : MemoryCacheの設定

.net framework 4.0からMemoryCacheクラスが使えます。 MemoryCacheにはこんな機能があります。

  • メモリ使用量の上限を設定できる。
  • キャッシュエントリの優先順位が設定ができる。
  • 時間経過によるキャッシュエントリの削除ができる。エントリごとに個別に設定可能。
  • キャッシュエントリが削除される前後にイベントが発生する。
  • キャッシュエントリに対応したファイルやデータベースの更新をチェックする機能があるらしい。

残念なことに現在のキャッシュエントリの総量を得る方法は見つかりませんでした。 (まだざっとドキュメントに目を通しただけなので見落としてるかもしれません。) でもまぁ、それ以外の使いそうな機能は一通り用意されていますね。 便利そうです。

MemoryCacheを使うには参照の追加(System.Runtime.Caching)が必要です。 デフォルトのキャッシュを使うにはstaticプロパティのMemoryCache.Defaultにアクセスします。

MemoryCacheの設定には全体設定とエントリごとの設定があります。 エントリごとの設定についての説明はここでは省略。 CacheItemPolicyについて適当に調べてみてください。 ここでは全体設定について説明します。 全体設定には次の3つがあります。

  • CacheMemoryLimit
  • PhysicalMemoryLimit ... 注) 割合を指定
  • PollingInterval

これらの設定は、C#のコード上では読み取り専用プロパティになっています。 コンストラクタで設定するしかありません。 デフォルトキャッシュの設定を変えたい場合、デフォルトキャッシュのコンストラクタはコードから触れないので別の手段で設定することになります。 その手段とはアプリケーション構成ファイルです。

  • visual studio上ではApp.config
  • ビルド後は実行ファイル名.exe.config

例えばこんなふうに書けばアプリケーション毎に設定を変更できます。 設定項目名がプロパティとは少し違うので注意。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.caching>
    <memoryCache>
      <namedCaches>
        <add name="Default"
                cacheMemoryLimitMegabytes="2000"
                physicalMemoryLimitPercentage="60"
                pollingInterval="00:02:00" />
      </namedCaches>
    </memoryCache>
  </system.runtime.caching>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

参考サイトはmsdnのこちらのページ、

なんですけど、現時点ではちょっと間違いがあるんですよね。

  • 誤 : physicalMemoryPercentage
  • 正 : physicalMemoryLimitPercentage
  • 誤 : default(先頭小文字)
  • 正 : Default(先頭大文字)

.NET Framework 4.5 用の説明らしいので古い情報ではないとは思うんですけど、さて?

まぁともかく、これでデフォルトキャッシュの設定は変更できます。 アプリケーションを実行して、MemoryCache.Default.CacheMemoryLimitなどの値を見れば変更されているのが確認できます。 アプリケーションに依存しない設定方法があるっていうのは用途によっては便利ですね。

デフォルトのキャッシュを使う場合はこれでok …… というかこういう手段しか発見できなかったんですが、いくつか不満があります。

  • アプリケーション構成ファイル以外の独自形式の設定ファイルを使うとき、デフォルトキャッシュの設定ができない。
  • コード上で動的にキャッシュサイズを変更することができない。
  • アプリケーション構成ファイルに設定を書くので、ユーザーに設定を変えられたくない場合でも設定変更の禁止ができない。

それを解決するには、デフォルトではないMemoryCacheを自分で作ります。 例えばこんなコードです。

class Util
{
    private static readonly string MEMORY_CACHE_NAME = "app";
    private static readonly MemoryCache _cache;
    static Util()
    {
        var values = new NameValueCollection();
        values.Add("cacheMemoryLimitMegabytes", "2000");
        values.Add("physicalMemoryLimitPercentage", "60");
        values.Add("pollingInterval", "00:02:00");
        _cache = new MemoryCache(MEMORY_CACHE_NAME, values);
    }
}

このコードではUtilクラスの静的コンストラクタでインスタンス化をしていますが、キャッシュを使う前に実行するなら別のタイミングでもokです。 実際には設定ファイルを読んだ後とかにインスタンス化することになるでしょう。

MemoryCacheのコンストラクタにはcacheMemoryLimitMegabytesなどの引数はありません。 設定項目はNameValueCollectionに収めて渡すことになります。