2013-03-25 7 views
17

Hash-consingは、指定されたオブジェクトのコピーを1つだけ保持します。つまり、2つのオブジェクトが意味的に等しい場合(同じ内容の場合)、それらは物理的に等しくなければなりません(メモリ内の同じ場所)。この手法は、通常、グローバルハッシュセットを保持し、ハッシュセット内のオブジェクトと等しくない場合にのみ新しいオブジェクトを作成することによって実装されます。F#のハッシュコンサインと.netの弱いハッシュテーブル。

さらに、ハッシュテーブル内のオブジェクトは、ハッシュテーブル以外のオブジェクトによって参照されない場合は収集可能である必要があります。さもなければ、ハッシュテーブルには弱い参照が含まれているはずです。

問題は、一定の時間が必要であるため、さらに浅いハッシュと平等テストを必要とするため、さらに複雑になります。したがって、オブジェクトには、新しいオブジェクトがテーブルに追加されるときに増分される固有の識別子があります。

System.Collections.Generic.Dictionary<key, node>を使用する実装があります。keyは、ノードの浅い要約(デフォルトのハッシュと等価性テストに適しています)を与えるタプルであり、nodeがオブジェクトです。唯一の問題は、Dictionaryがノードへの強い参照を保持していることです!

DictionaryWeakReferenceを使用できますが、これはダングリングリファレンスを指すキーを解放しません。

System.Runtime.CompilerServices.ConditionalWeakTableを使用している提唱者もいますが、このクラスは逆の処理をしているようです。キーを収集するときに値を解放しますが、値を収集するときにはキーを解放する必要があります。

一つはSystem.Runtime.CompilerServices.ConditionalWeakTable<node, node>を使用して試みることができるが、私は、カスタムハッシュと平等のテストが必要になる...とConditionalWeakTableではなく、デフォルトのハッシュ関数を使用して、GetHashCode()仮想メソッドを使用するないを文書化されています。

私の質問:値が弱い参照を保持し、参照がぶら下がるとキーを解放するDictionaryのいくつかの同等のものがありますか?

+0

値を収集するとすぐにキーを解放する必要がありますか?または、要件を緩和して、ちょっと後でキーを解放することはできますか? –

+0

私はそれらをすぐに解放する必要はありません - それは私がそれらが蓄積し、無駄に多くのメモリを消費したくないということだけです。私は、別のスレッドを実行して定期的に参照がついていないキーを殺すことを考えましたが、これは複雑で同時実行エラーが発生しやすいようです。 –

+0

それは価値があるのですが、私は 'Weak'モジュールのハッシュテーブルと' WeakHashMap'を使ったJava実装を使ってOCaml実装をしています。 –

答えて

3

CWTはハッシュコンサインの問題を解決しないというのは正しいことです。なぜなら、そのキーは参照の平等を前提としているからです。しかし、CWTがキーや値を保持していないことを指摘する価値があるかもしれません。私のマシン上で

open System.Collections.Generic 
open System.Runtime.CompilerServices 

let big() = 
    ref (Array.zeroCreate (1024 * 1024) : byte []) 

let test1() = 
    let d = Dictionary(HashIdentity.Reference) 
    for i in 1 .. 10000 do 
     stdout.WriteLine(i) 
     let big = big() 
     d.Add(big, big) 
    d 

let test2() = 
    let d = ConditionalWeakTable() 
    for i in 1 .. 10000 do 
     stdout.WriteLine(i) 
     let big = big() 
     d.Add(big, big) 
    d 

test1メモリ不足とtest2成功:ここで少しテストがあります。これは、CWTがキーだけでなく値を保持していない場合にのみ発生するようです。

ハッシュコンプリートの場合、Artemがコメントに示唆しているものかもしれません。これはあまりにも複雑に聞こえる場合、それはまた、多くの意味は、単にユーザーコントロールを与えることになり、言う:

let f = MyFactory() // a dictionary with weak reference values hidden inside 
f.Create(..) : MyObject // MyObject has no constructors of its own 
f.Cleanup() // explicitly cleans up entries for collected keys 

その後、あなたは、スレッドを導入する必要がある内部の仕組みGC勉強、または任意の魔法を行いません。ライブラリのユーザーは、テーブル全体を収集する工場オブジェクトをクリーンアップするか、単に「忘れる」ことが適切な場所を決定することができます。

+1

私はCWTを使用しようとしましたが、テーブルの中に置かれたデータはすぐに収集されたように見えます(キーが到達不能になるとすぐに値が収集されるためです)。あなたはCWTからデータを回復しようとしましたか? CWTはデータ型からハッシュコード関数を使用せず、代わりにハッシュコンプリントには適さないデフォルトのハッシュ関数を呼び出します(一意の識別子で浅いハッシュを必要とする)ので、AからAへCWTを使用することは不可能です。 1つの解決策は、CWTソースコードをコピーしてそれを適合させることです。 –

+0

@monniaux:はい、私はCWTがハッシュコンサインには適していないことに同意します。 OCamlの弱いテーブルがここではっきりと勝つ。 CWTのデータを回復するには、キーを押し続けても問題ありません。これは、そのために設計されたものです。はい、あなたが良い解決策を見つけたり、自分自身でハッシュコンサインを書くことができれば、ここに投稿してください。 – t0yv0

関連する問題