弱い弱いテーブルテーブルLua



Weak Weak Table Table Lua



再現

弱いテーブル (弱いテーブル)は非常に興味深いものであり、C ++ / Javaや他の言語はそうではありません。弱いテーブルが定義されています:弱いテーブルは、要素が弱参照であるテーブルです。 弱い弱い参照テーブルと呼ばれるテーブル要素弱い参照には強い参照があるので、非参照を持つ参照があります 。 PCTには、変数、値、型、オブジェクトという基本的な概念が必要です。

(1) 変数と値 :Luaは動的に型付けされた言語です。つまり、 Luaでは、変数型はなく、何でもかまいませんが、値型があります 、など Luaは変数型の定義のようなものではありません 。加えて、 すべての値はLuaファーストクラス値(ファーストクラス値)にあります。



(二) Luaには8つの基本的なタイプがあります :なし、ブール値、数値、文字列、関数、ユーザーデータ、スレッド、テーブル。 Nil nil変数は、他のタイプの基本7を区別するために、主な目的がnilallタイプ以外のタイプであるタイプです。

(3) オブジェクトオブジェクト:テーブル、関数、スレッド、ユーザーデータ。すべて参照型変数であるこれらの型の値に関して(変数型データ自体は保存されませんが、そのポイント)。割り当て、送信パラメータ、および関数がこれらの値の操作への参照を返すため、コピー動作は作成されません



弱いテーブル定義-弱い参照

弱テーブルは弱参照を使用することであり、多くの範囲のメモリの制御です。
  • 弱いテーブルはテーブルであり、メタテーブルがあり、メタテーブルで定義された__modeフィールドがあります
  • 参照表が弱い弱参照(WeakReference)、弱い参照オブジェクトの参照カウントは変更されません 言い換えると、オブジェクトがそのオブジェクトへの弱参照にすぎない場合、gcはオブジェクトのメモリを自動的に再利用します。
  • __modeフィールドは、次の3つの値を取ります。k、v、kvkはtable.keyが弱いことを表します、つまりテーブルは自動的にGCキーになりますvはテーブルを表します。値は弱いです、つまり、テーブルの値は自動的にgc kVになり、2つの組み合わせになります。いずれにせよ、キーと値の1つがGCである限り、キーと値のペアはテーブルから削除されました。

テーブルへの通常の強い参照の場合、オブジェクトをテーブルに配置すると、参照が作成されます。残りの要素に要素のテーブルへの参照がない場合でも、gcはオブジェクトを復元しません。 したがって、2つの選択肢しかありません。手動でテーブル要素を解放するか、それらを永続メモリにするかです。

strongTable = {} strongTable[1] = function() print('i am the first element') end strongTable[2] = function() print('i am the second element') end strongTable[3] = {10, 20, 30}

print(table.getn(strongTable))– 3
collectgarbage()
print(table.getn(strongTable))-3プログラミング環境では、nilのタイミングを手動で決定するためのキーを割り当てない場合があります。ただし、リリースする前に、後で実行するユーザーがリリースされる必要があります。キーと値のペア。今回は弱いテーブルが重宝します



weakTable = {} weakTable[1] = function() print('i am the first element') end weakTable[2] = function() print('i am the second element') end weakTable[3] = {10, 20, 30} setmetatable (weakTable, {__mode = 'v'}) - set table weak print(table.getn(weakTable)) -->3 ele = weakTable [1] - to add a reference to the first element collectgarbage() print (table.getn (weakTable)) -> 1, referred to as a first function, not gc ele = nil - release references collectgarbage() print (table.getn (weakTable)) -> 0, there is no other references, all gc

もちろん、実際のコードの過程で、手動でガベージを収集する必要はありません。関数はバックグラウンドで自動的に実行され、独自の動作サイクルと法則があり、プログラマーには透過的であるためです。もう一つの例:

a = {} b = {} setmetatable(a,b) b.__mode = 'k' --now 'a' has weak keys

key = {}-最初のキーを作成します
a [キー] = 1

key = {}-2番目のキーを作成します
a [key] = 2

ペアのk、vの場合(a)
印刷(v)-1 2
終わり
collectgarbage()-ガベージコレクションサイクルを強制します
ペアのk、vの場合(a)
印刷(v)-2
-[[2番目のキー= {}の割り当ては、最初のキーの値を上書きします。ガベージコレクターが機能するとき、
重要な参照ポイントがない他の場所では、それが収集されるため、テーブル内の対応するエントリも削除されます。
ただし、2番目のキーである変数は、アクティブキーによって占有されているため、収集されません。 -]]
終わり

注意を払う、 の弱いテーブルから収集できるのはオブジェクトのみです。数値やブール値タイプなどは収集されません。

いくつかのニュアンスの文字列について: 上記の観点から、文字列を収集することはできますが、達成するために それらはまだ他の収集可能なオブジェクトとは異なります。テーブルや関数などの他のオブジェクトを作成するためのもので、それらはすべて表示されます。といった、 Lua {}のときに遭遇するたびに、新しいテーブルが作成されますこの関数()はいつでも。 。 。新しい機能の確立を終了する(実際には閉鎖) 。ただし、Lua see'a '..' b 'は、新しい文字列が作成されたときに作成されますか?システムにすでに文字列「ab」がある場合、どうすればよいですか? Luaは新しいものを再構築しますか?コンパイラは実行する前に文字列を作成できますか?重要ではありません。これらは実装の詳細です。したがって、 プログラマーの観点からは、文字列値はオブジェクトではありません。 したがって、数値またはブール値として、weakからではない文字列はテーブルから削除されます(収集された値に関連付けられている場合を除く)。

弱いアプリケーション例

t = {} - used as a key table value of t key1 = {name = 'key1'} t[key1] = 1 key1 = nil

-キーおよびtの値としてテーブルを使用する
key2 = {name =“ key2”}
t [key2] = 1
key2 = nil

-ガベージコレクションを強制する
collectgarbage()

キーの場合、ペア(t)の値は
print(key.name…“:”…value)
終わり
-出力
–key1:1
–key2:1割り当て後にtを指定している間、key1とkey2はnilに割り当てられます。ただし、表のキー値に追加されているため、廃棄物として扱われません。

つまり、値はnil key1自体ですが、tに格納されているコンテンツへのポイントがまだあります。 key2も同じ状況です。これで、最終的にkey1とkey2の名前フィールドを出力できます。

テーブルを別のテーブルのキー値として配置すると、テーブルの値がゼロになることを期待して、フィールドが削除される別のテーブルも削除されます。達成する方法は?
この時間は弱参照テーブルを使用するために必要であり、実装はテーブル要素を使用する弱参照テーブルです。
コードを見てみましょう。前とほぼ同じですが、コードを追加したのは次のとおりです。

t = {} - t to set a table element, increasing __mode element method, assigned to 'k' setmetatable(t, {__mode = 'k'})

-tのキーテーブル値として使用されます
key1 = {name =“ key1”}
t [key1] = 1
key1 = nil

-キーおよびtの値としてテーブルを使用する
key2 = {name =“ key2”}
t [key2] = 1
key2 = nil

-ガベージコレクションを強制する
collectgarbage()

キーの場合、ペア(t)の値は
print(key.name…“:”…value)
終わり
-出力がnulltが作成されると、すぐに元がテーブルに設定され、「k」文字列にテーブルyuan__modeフィールドが割り当てられることに注意してください。今回コードを実行すると、すべてのフィールドtが存在しないため、何も出力されません。
これは弱参照テーブルの1つであり、この要素メソッドの値に文字列 'k'が含まれている場合、キーテーブルに代わって弱参照が__mode要素メソッドに追加されます。
参照用の残りのキー値がキャンセルされると(nilに設定されると)、このフィールドのこのテーブルは削除されます。

素人の用語では、tはキーの弱参照に設定されているため、t [key1] = 1の後に実行すると、tはこのフィールドに存在します。続いて、key1 = nilを実行しました。今回は、それ自体の外側のtに加えて、key1を保持するための参照がどこにもないため、key1フィールドは削除されます。

単純なアプリケーションの弱いテーブル-メモリ機能

かなり一般的なプログラミング手法は、時間にスペースを使用することです 。あなたはできる 結果を最適化するメモリ関数。同じパラメータで関数を再度呼び出すと、メモリの結果が自動的に返されます。

共通のサーバーを想像してみてください。リクエストを受信すると、文字列Luaコードが含まれます。リクエストを受信するたびに、loadstring load a stringを呼び出してから、処理関数を呼び出します。ただし、loadstringは「巨大な」関数であり、一部のコマンドはサーバーで頻繁に使用されます。後続の呼び出しとリアロードストリングcloseconnection()を繰り返す必要はありません。サーバーは、ロードストリングを使用することにより、メモリテーブルのセカンダリ結果にすることができます。 loadstringを呼び出す前に、サーバーは文字列が変換された結果であるかどうかをテーブルで調べます。何も見つからない場合、(そしてこの場合のみ)サーバーはloadstringを呼び出し、結果を補助テーブルに入れます。パッケージの機能として操作できます。

local result = {} function mem_loadstring(s) if result[s] then return result[s] else local res = loadstring(s) result[s] = res return res end end

このプログラムのストレージ消費量は膨大になる可能性があります。それでも、予期しないデータの冗長性につながる可能性があります。一部のコマンドは何度も繰り返し実行されますが、一部のコマンドは1回しか実行されない場合があります。徐々に、このテーブルは、遅かれ早かれ処理後に呼び出されたコマンドサーバーのすべての結果を蓄積し、サーバーのメモリをタンブルしました。弱いテーブルは、この問題の簡単な解決策を提供します。これがテーブルになる場合 各ガベージコレクションサイクルには弱い値があり、現在の期間に使用されていないすべての結果(通常はほとんどすべて)が削除されます。

setmetatable(results、{__ mode = 'v '})-値を弱くする

実際、テーブルインデックスインデックスは文字列に似ていることが多いため、必要に応じて、テーブルをすべて弱く設定できます。

setmetatable(results、{__ mode = 'kv '})

メモリテクノロジは、ある種のオブジェクトの一意性を維持するのにも役立ちます。 たとえば、システムがテーブル赤、緑、青の特定の組み合わせによる色表現。新しいリクエストごとに生成されるナチュラルカラートナーの新しい色:

function createRGB (r, g, b) return {red = r, green = g, blue = b} end

メモリ技術を使用して、同じ色で保存された同じ結果を適用できますテーブルin。各色のみを確立するためキー 、カラーインデックスインデックスに接続されたセパレータを使用するだけです

local res = {} setmetatable(res,{__mode = 'v'}) function createRGB(r, g, b) local key = r .. '-' .. g .. '-' .. b if res[key] then return res[key] else local newcolor = {red = r,green = g,blue = b} res[key] = newcolor return newcolor end end

興味深い結果は、2つの同時色が同じテーブルで表されるため、ユーザーが元の等式演算子を使用してカラーマッチング操作を識別できることです。注意を払う、 ガベージコレクターは結果テーブルで何度もクリーンアップするため、同じ色が異なる時間に異なる物語で表現される場合があります。ただし、特定の色が使用されている限り、その色は結果から削除されません。したがって、他の色と比較して十分長く生き残ることができる色はいつでも、生き残りの結果を反映しています。

弱い単純なアプリケーションテーブル-属性関連オブジェクト

単純なアプリケーションの弱いテーブル-デフォルトの価値のあるテーブル

- [[In the first solution, we will default to using a weak table and each table vaules linked: Use the default vaules to weak table and each table is associated -]] local defaults = {} setmetatable(defaults,{__mode = 'k'}) local mt = {__index = function(t) return defaults[t] end} function setDefault(t,d) defaults[t] = d setmetatable(t,mt) end - [[If the default is no keys weak, and it will all tables with default values ​​set forever. In the second method, We use different metatables to save different default value, but when we re-use a default value, the same reuse the same The metatable. This is a typical use of memory technologies: -]] local metas = {} setmetatable(metas,{__mode = 'v'})

関数setDefault(t、d)
ローカルmt = metas [d]
mt == nilの場合
mt = {__index = function()return d end}
metas [d] = mt--メモ化
終わり
setmetatable(t、mt)
終わり

この場合、弱い値を使用します。メタテーブルは使用できません。リサイクルできます。

これらの2つの方法を一緒にすると、どちらが良いですか?一般的に、状況に応じて。それらは同様の複雑さと同様のパフォーマンスを持っています。 最初の方法では、デフォルト値のそれぞれにいくつかのテキストテーブルを追加する必要があります(デフォルトのエントリ)2番目の方法では、さまざまなデフォルト(新しいテーブル、新しいクロージャ、新しいエントリMetas)のそれぞれにテキストを追加する必要があります。 。したがって、プログラムに数千のテーブルがあり、これらのテーブルの数が少ない場合は、デフォルト値が異なる2番目の方法が明らかに優れています。一方、同じデフォルトの値を共有できるタブが数個しかない場合でも、最初の方法を使用します。