Hatena::ブログ(Diary)

Ko-Taのバ・ー・ルのようなもの

2007-10-13

uCache.pas

簡単なキャッシュ機構を以前組んだので、整理してアップしておこうかと思います。


・ダウンロード

http://kota.dokkoisho.com/#Cache


・概要

メモリキャッシュ・ファイルキャッシュなど任意のオブジェクトのキャッシュを実現するクラスユニットです。

3命令ほどoverrideするだけで完成です。

あとは勝手に管理してくれます。

と言っても、全てに適用できるわけではなく、内容が変化しない静的なオブジェクトに限ります。


・利点

ファイル読み込みなどではかなりの効果を発揮してくれるでしょう。大量の細かいファイルはサーチ時間で結構食いますし。

PNGなどの圧縮ファイルの読み込みだと、展開プロセスをスキップできるので更に効果が望めるはず。

また、同一ファイルを複数読み込むような場合は、(オブジェクトのリンクを張るため)重複した無駄なメモリ消費も最適化してくれるので便利ですネ。

(3DModelのTextureなんかに使うと効果的かと思います。モデル間の重複テクスチャとか最適化してくれるので)

と言った案配です。


・サンプル

ビットマップ読み込みキャッシュ(TBitmapCache)のサンプルコードが入っています。

これを元にチョコチョコっと弄れば色んなキャッシュが乱造出来るかと思います。


・使い方

キャッシュクラスを作ったら読み込みと解放にキャッシュのメソッドを挟み込みます。

付属サンプルのTBitmapCacheの例です。

■読み込み
begin
  //キャッシュ生成
  BitmapCache := TbitmapCache.Create;
  BitmapCache.SetLimitSize(1024*1024*16); //16Mキャッシュ
  //画像読み込み
  bmp01 := BitmapCache.Load(nil,'sample.bmp');
  〜
end;

■解放
begin
  〜
  //画像解放
  BitmapCache.UnLoad(bmp01);
  //キャッシュ解放
  BitmapCache.Free;
end;

・キャッシュの動き

最もオーソドックスな管理法で、生存時間が0になるか、キャッシュの制限サイズを超えた場合、最も古いものから解放していきます。

ヒットすると生存時間は最大値に再セットされます。

ヒット数(Load数)を用いて溢れたときに殺す優先度も組み込むと良いのかもしれませんがそれはまた今度。


・キャッシュについて

http://e-words.jp/w/E382ADE383A3E38383E382B7E383A5.html

ほへー。


・履歴

2007/10/31...ReadMe修正

2007/10/13...ver1公開

ほにゃららほにゃらら 2007/10/15 16:05 キャッシュちっくなコードは”頻繁に”書きますよー♪
すなわちそれはちっともライブラリ化できてなくて使いまわせていない俺(滝汗

Ko-TaKo-Ta 2007/10/15 18:52 実際のオブジェクトの動きは様々で、必ずしもこのようなライブラリが適用できない場合は少なくないですよね…。
うちのプログラムに「$ScreenShot.bmpでスクリーンショットをファイルIOから読み込む」ということをやってたりするのですが、
その場合同じファイル名でも時間によって変化しちゃうので、これをまた継承させて色々例外処理をぶち込んだりとかしてなんとかやりくりしてます…ソース汚いです。

tobytoby 2007/10/27 14:50 これってば、
ソフト起動時に、全部読みこんじまえ的なソフト向けではなく、
リソースが多くて、遅延ロードする的な(ADVゲームとか?)向けのキャッシュ機構でしょうか?
キャラの立ち絵や背景が、全部はメモリに入りきらないくらい一杯あって、それぞれが何回も表示されたり、されなかったりするようなー。

もしくはー、大量の効果音をキャッシュとか、夢がひろがりんぐ。

面白いのは、いわゆる OSのファイルIOレベルのキャッシュではなく、
オブジェクトの参照を返してしまうというキャッシュなんですね。
これだと、サンプルもそうですが、かなりの高速化が見込めそう。
(そもそもファイルのIO程度のキャッシュで間に合うのだったら、OSまかせでもいいですもんね)

メモリー容量を指定できる辺り、実戦向きだなーと思いました。



■今後の課題的な何か。

・Search(); の線形探索は、リソース数が大きくなった時に、
クリティカルな場面では、速度的にかなり不利なので、
(せっかくHashを求めているくらいだし)Hashや、Mapで実装してみる。

これは、自分がリアルタイムのアクションゲーム開発などがメインだから、そう思ってしまうのかと。

(C#や、C++/STLなら、HashやMapはライブラリ呼び出し一発なのに、
クソーって思うところですが、(Rubyならライブラリすらいらん)
Delphiだと、標準の THashedStringList はショボーンで、
JCLの JclHashMap は激しく使いにくいので、結局自作という罠。
TVarRecか、Variantを返したり、インチキ template 使用の Hash構造を
一回、ライブラリ化しとくと他にも使い回しが効いてよいです)

・今なら、CustomAnsiLowerCaseあたりは、WideString対応でいいのかも

・ファイル更新感知機能がほしい!
デバッグ時用に、リアルタイムで更新したら、
自動で再読み込みできると、ウマーですね。


■以下、気になった点。

・どうでもいー、ReadMe.txtの間違い指摘。
Unit1.pasみたら一発でわかりましたが、パッと見、混乱しましたw

「■任意のキャッシュを作る」の、
”TMemoryStreamCache” -> ”TBitmapCache”
”TMemoryStream” -> ”TBitmap”


■他
キャッシュ構造はすごく欲しかったので、
ちょっと弄って使ってみようかなーと思っとります。
(特に、外部スクリプトとか、効果音の再生)

長文すんません。
自分のブログにかけって感じ。

Ko-TaKo-Ta 2007/10/28 11:35 >遅延ロードする的な(ADVゲームとか?)向けのキャッシュ機構でしょうか?
そう言ったケースだと効果が見込めますねーって代物です。マップ切り替え時の重複読み込みなんかを自動的に最適化するのが目的となります。
また、キャッシュサイズが0でも、今読み込まれてるものであればそのオブジェクトのポインタ(クラスのアドレス)を返すので、不要な重複読み込みも自動的に最適化してくれます。
実はこっちがメインなんです。

>オブジェクトの参照を返してしまうというキャッシュなんですね。
そです。ObjectCacheです。紛らわしくてごめんなさいね。もっと低レベル層のキャッシュはOSに任せちゃおうかなと思いまして。
高レベルでキャッシュしちゃって低レベルアクセスをスキップしちゃえ!ってなものであります。うへぇ。

>Hashや、Mapで実装してみる
そうです。かなりキャッシュが蓄積される場合(数万個)はこの処理では負荷がかかります。(あと容量オーバー時にソートも入るのでそこもなんとかしないといけないかも)
主に読み込みなんかを想定した数百個程度が想定ラインなので、リアルタイムでなにかをキャッシュさせる場合はmapあたりが無難な気がします。
(動的なので検索List・Threeの変更が素早いアルゴリズムが好ましいです)
改造はよろしく!

>今なら、CustomAnsiLowerCaseあたりは、WideString対応でいいのかも
WideStingベースに書き直すべきかも考えましたが、大人の都合でやめました(笑)。単にキャッシュの識別ID用にしか利用していないのでほとんど変更無くいけそうな気もします。
なんなら、最初に「type CustomString=String/WideString」みたいに宣言しちゃって型を統一しても良いかもしれません。ぼくver6なので。

>ファイル更新感知機能がほしい!
なるほどー。最も簡単なファイル監視せずに全再読込でも良さそうですね。(全部読み込んでもそんなに時間かからないと思うので)
でもこれはこのクラスを派生させることで実装できるので、兄貴にお任せしようと思います!オス!

>誤字
すんませーん。ソースコピペじゃなくて新規に書いたのでやっちゃったかも。もっかいみときまーす。


私用ではsha256なりを用いて生データのハッシュをidとしてキャッシュさせてたりしてます。
ファイル名が違っても全く同じデータならキャッシュしちゃうということがががが。ちょっと重複怖いけど

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証