簡介
如果已產生大量的物件,系統垃圾收集可能會導致效能問題。此頁面討論相關問題並提供避免這些問題的點子。
將建立的物件降到最低
問題:基本上,我想將配置的暫時記憶體降到最低,這樣就可以減少呼叫 GC 的頻率(並可能減少每次 GC 的影響)。有人可以提供關於這個主題的一些提示嗎?例如,假設我在函式 A 內部宣告了局部變數,這些局部變數每次呼叫 A 時會配置記憶體嗎?
(ET)不會。局部變數會保留在堆疊中,而且不會影響 GC。這些結構會建立一個新的垃圾收集物件
-
a..b
(僅為範例;任何產生字串的結構,例如 strsub()
[*1] 或 lua_pushstring()
。)
- 每一個新的字串都會建立一個新的物件。Lua 有獨特的字串,這表示每個可能的字串在 Lua 內只存在一次。如果出現新的字串,Lua 會先檢查字串池中是否已存在該字串。如果已存在,就會使用對應較舊字串的參考。如果不存在,就會建立新的字串物件並將其放入字串池中。GC 會檢查字串池是否有未使用的字串並將其釋放。因此,建立許多獨特的字串會破壞 GC。亦即這在 GC 方面很糟糕
for i=1,100 do x="foo"..tostring(i) end -- 100 new strings
- 注意:程式碼區段保留對應字串常數的參考(如上述「foo」)。因此,只要這個函式存在,字串就會存在於字串池中;每次執行函式不用建立字串。
- 每次執行 table 建構函式時,就會建立新的 table。盡量重複使用 table。甚至可以進一步建立並使用管理未用 table 池的 newtable/freetable 函式。這樣就可以為 table 取得舊式記憶體管理,但也會取得舊問題 ;-)
- 執行函式陳述式會建立封閉(注意:不是呼叫函式,而是執行函式陳述式!)。一般上對 GC 沒有太大的影響,但如果迴圈內有函式陳述式,可能會建立大量的垃圾。亦即
for i=1,100 do foo(function() end) end -- bad for GC
- 會建立 100 個函式封閉。
- 每次呼叫變數參數函式時,都會建立一個 ellipsis 的 table(儲存在「
arg
」中)。(注意:從 Lua 5.2 開始,或使用 LuaJIT 時,此說法不再成立。)
- 在 Lua 4.0(以及 3.x)中,userdata 物件的處理方式類似於字串。如果指標值和標記相同,這些物件就是相等的。Lua5 呢?
- 嗯,這些會載入/編譯新的程式碼,而且會建立字串和(GC)程式碼區段。
釋放局部變數
問題(以上為續):因此,離開函式時會釋放所有局部字串或 table 嗎?
變數是儲存物件的地方(事實上,除了數字以外它只儲存物件的指標)。物件是否為數字、表格或其他什麼東西都不用變數費心。而區域變數本身不是垃圾收集的物件。因此,你可以使用它們而無需建立中介物件。我想,那應該是原作者的意思。
- 「因此,你可以使用它們而無需建立中介物件。」這需要澄清嗎?變數本身不建立 GC 物件,但其值會。你可以使用區域變數,參考其他現有的物件,而無需建立需要收集的物件。但是,你不能建立新的物件成為區域,而無需建立日後需要收集的物件。
關於儲存在區域變數內的物件:在區域變數不再使用後,GC 可能會收集儲存在區域變數的物件。物件的實際釋放與函式範圍或變數存在時間無關。GC 在特定時間點執行並釋放任何 L 無法再存取的物件
[*1] strsub
存在於 Lua 4 中,而不是 Lua 5 中。
最近變更 ⋅ 偏好設定
編輯 ⋅ 歷史記錄
最後編輯於 2014 年 4 月 18 日下午 7 點 12 分(GMT)(diff)