1

警告:

問題は、ここで説明した luatraverse スクリプトが宣伝どおりに機能せず、オブジェクトへのすべての参照が見つからないことにあると確信しています。私の例では、オブジェクトが参照されている場所を見つけたため、そのコレクションが妨げられましたが、スクリプトによって報告されませんでした。

したがって、この質問の基本的な前提には多少の欠陥があります。

背景:

ゲームBitfighterのスクリプト エンジンの強化に取り組んでいます。メモリが適切に解放されているとは確信していません。そこで、以下のスクリプトの形式でテストを作成しました。

3 列のユーザーデータを出力します。列 1 は、他では使用されないと予想されるユーザーデータであるため、collectgarbage 関数によって破棄する必要があります。2 列目と 3 列目は収集する必要がないと思われるオブジェクトです。

問題:

列 1 のユーザーデータは変化しないため、収集されていないと思われます (列 2 と 3 は期待どおりに動作します)。状況をさらに明確にするために、この問題で言及されている luatraverse スクリプトを使用しています。これは、obj100 自体に格納されている obj100 への参照が 1 つしかないことを確認しているようです。countreferences (local x = obj100) を実行する直前に割り当てを追加しようとしましたが、予想どおり、countreferences はオブジェクトが 2 回参照されていることを報告しました。

質問:

1) この出力を正しく解釈していますか? obj100 は本当に収集されませんか? または、同じメモリアドレスが何度も再利用されている可能性はありますか?

2) 特定の Lua オブジェクトを参照しているものを確認する luatraverse スクリプトよりも良い方法はありますか?

コード:

 -- Every 2 seconds, find two objects with ids 100 and 200, and print their addrs
 -- No reference is kept for object 100, so its userdata might change over time
 -- Object 200 is held by objHolder, so its userdata should remain constant

 -- Obj200 should remain constant over time; obj100 can vary.  
 -- objHolder should be constant, obviously

 local ltraverse = require("luatraverse")


 function printIds()
    local obj100 = levelgen:findObjectById(100)
    local obj200 = levelgen:findObjectById(200)
    print("Obj 100:" .. tostring(obj100) .. " Obj 200:" .. 
           tostring(obj200) .. " Held:" .. tostring(objHolder))


    print(ltraverse.countreferences(obj100))

    obj100 = nil
    obj200 = nil

    collectgarbage()
 end

 function main()
    -- levelgen:findObjectById is a local game command that
    -- creates a userdata for an object
    local obj100 = levelgen:findObjectById(100)
    objHolder    = levelgen:findObjectById(200)     -- not local, global

    assert(obj100)
    assert(objHolder)

    print("Column 1 can vary; 2 and 3 should be constant")
    print("=============================================")

    print("Obj 100:" .. tostring(obj100) .. " Obj 200:" .. 
         tostring(objHolder) .. " Held:" .. tostring(objHolder))

    obj100 = nil

    -- Run a function every 2 seconds
    Timer:scheduleRepeating(printIds, 2000)
 end 

出力:

 Column 1 can vary; 2 and 3 should be constant
 =============================================
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280

 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 Obj 100:userdata: 02FC9700 Obj 200:userdata: 02FAD280 Held:userdata: 02FAD280
 1
 ... and onward to infinity ...
4

1 に答える 1

0

Bitfighter についてはわかりませんが、ここで間違ったことを測定していると思います。

この行は、本質的に実際の C++(?) オブジェクトを指す新しい Lua ユーザーデータ オブジェクトを作成します。

local obj100 = levelgen:findObjectById(100)

次の行の後半で、そのユーザーデータを指す Lua 内の参照の数を出力します (obj100実際のデータではありません)。

print(ltraverse.countreferences(obj100))

オブジェクトへの 1 つの参照を使用してそのオブジェクトを作成したため、これは常に 1 になります。

参照/Lua オブジェクトはおそらく収集されますが、それは表示されません。同じオブジェクト ID を要求しているため、実際のユーザーデータ (ポインター) は常に同じです。したがって、関連するデータが他のコードによって移動/再割り当てされない限り、この値を変更してはなりません。

しかし、最終的には、これは何をlevelgen:findObjectById()返すかによると思います。次の行を試してみるとどうなりますか?

local temp
local obj100 = temp = levelgen:findObjectById(100)
于 2013-01-25T23:35:33.547 に答える