天天看點

學習Cocos2d-x Lua:Lua基礎之弱引用table

這個系列我們主要學習Cocos2d-x Lua,總結Lua開發過程中所涉及的知識點,以及在開發過程中如何使用Cocos Code IDE。這一篇講解引用table的問題。

1.自動記憶體管理的缺陷

我們都知道,Lua是具備自動記憶體管理的,好吧,也許有些朋友不知道。

我們隻管建立對象,無須删除對象(當然,對于不要的對象你需要設定一下nil值),Lua會自動删除那些被認為是垃圾的對象。

問題就出現在,什麼對象才是垃圾對象,有些時候,我們很清楚某個對象是垃圾,但是,Lua卻無法發現。

比如這樣一個例子:

t = {};
   
-- 使用一個table作為t的key值
key1 = {name = "key1"};
t[key1] = 1;
key1 = nil;
   
-- 又使用一個table作為t的key值
key2 = {name = "key2"};
t[key2] = 1;
key2 = nil;
  
-- 強制進行一次垃圾收集
collectgarbage();
   
for key, value in pairs(t) do
    print(key.name .. ":" .. value);
end      

這段代碼有點複雜,首先以一個table,叫做t。然後建立一個新的table——key1,這個key1作為t的key值,給t新增了一個字段,指派為1。

同樣的,key2也作為t的一個key值。

接着,調用了collectgarbage函數,可以不管它,我們隻要知道,它會讓lua進行一次垃圾回收。

最後輸出t的所有字段,輸出結果如下:

[LUA-print] key1:1

[LUA-print] key2:1

這很符合常理,也在我們的預計當中,雖然我們在給t指派之後,key1和key2都指派為nil了。

但是,已經添加到table中的key值是不會是以而被當做垃圾的。

換句話說,key1本身已經是nil值,但它曾經所指向的内容依然存放在t中。key2也是一樣的情況。

是以我們最後還是能輸出key1和key2的name字段。

2.颠覆你的認知——弱引用table

剛剛舉例的隻是正常情況,那麼,如果我們把某個table作為另一個table的key值後,希望當table設為nil值時,另一個table的那一條字段也被删除。

應該如何實作?

這時候就要用到弱引用table了,弱引用table的實作也是利用了元表。

我們來看看下面的代碼,和之前幾乎一樣,隻是加了一句代碼:

t = {};
   
-- 給t設定一個元表,增加__mode元方法,指派為“k”
setmetatable(t, {__mode = "k"});
   
-- 使用一個table作為t的key值
key1 = {name = "key1"};
t[key1] = 1;
key1 = nil;
   
-- 又使用一個table作為t的key值
key2 = {name = "key2"};
t[key2] = 1;
key2 = nil;
   
-- 強制進行一次垃圾收集
collectgarbage();
   
for key, value in pairs(t) do
    print(key.name .. ":" .. value);
end      

留意,在t被建立後,立刻給它設定了元表,元表裡有一個__mode字段,指派為”k”字元串。

如果這個時候大家運作代碼,會發現什麼都沒有輸出,因為,t的所有字段都不存在了。

這就是弱引用table的其中一種,給table添加__mode元方法,如果這個元方法的值包含了字元串”k”,就代表這個table的key都是弱引用的。

一旦其他地方對于key值的引用取消了(設定為nil),那麼,這個table裡的這個字段也會被删除。

通俗地說,因為t的key被設定為弱引用,是以,執行t[key1] = 1後,t中确實存在這個字段。

随後,又執行了key1 = nil,此時,除了t本身以外,就沒有任何地方對key1保持引用,是以t的key1字段也會被删除。

3.三種形式的弱引用

對于弱引用table,其實有三種形式:

1)key值弱引用,也就是剛剛說到的情況,隻要其他地方沒有對key值引用,那麼,table自身的這個字段也會被删除。設定方法:setmetatable(t, {__mode = “k”});

2)value值弱引用,情況類似,隻要其他地方沒有對value值引用,那麼,table的這個value所在的字段也會被删除。設定方法:setmetatable(t, {__mode = “v”});

3)key和value弱引用,規則一樣,但是key和value都同時生效,任意一個起作用時都會導緻table的字段被删除。設定方法:setmetatable(t, {__mode = “kv”});

當然,這裡所說的被删除,是指在Lua執行垃圾回收的時候,并不一定是立刻生效的。

我們剛剛隻是為了測試,而強制執行了垃圾回收。

繼續閱讀