WoW:Lua object memory sizes: Difference between revisions
(One intermediate revision by the same user not shown) | |||
Line 55: | Line 55: | ||
Each function closure takes 20 bytes of RAM. The below code will use 20000 bytes: | Each function closure takes 20 bytes of RAM. The below code will use 20000 bytes: | ||
<pre> | <pre> | ||
for t=1,1000 | for t=1,1000 do | ||
x = function() end | x = function() end | ||
end | end | ||
Line 62: | Line 62: | ||
<pre> | <pre> | ||
local semistatic = "hi!" | local semistatic = "hi!" | ||
for t=1,1000 | for t=1,1000 do | ||
x = function() print(semistatic) end | x = function() print(semistatic) end | ||
end | end | ||
Line 68: | Line 68: | ||
However, upvalues that actually ''change'' use an additional 32 bytes. The below code will use 20000 + 4000 + 32000 = 56000 bytes: | However, upvalues that actually ''change'' use an additional 32 bytes. The below code will use 20000 + 4000 + 32000 = 56000 bytes: | ||
<pre> | <pre> | ||
for t=1,1000 | for t=1,1000 do | ||
x = function() print(t) end | x = function() print(t) end | ||
end | end | ||
Line 74: | Line 74: | ||
And finally, a mix: The below code will use 20*2*500 + 4*2*500 + 32*500 = 40000 bytes | And finally, a mix: The below code will use 20*2*500 + 4*2*500 + 32*500 = 40000 bytes | ||
<pre> | <pre> | ||
for t=1, | for t=1,500 do | ||
for i=1,2 | for i=1,2 do | ||
x = function() print(t) end | x = function() print(t) end | ||
end | end | ||
end | end | ||
</pre> | </pre> |
Latest revision as of 16:05, 13 October 2023
Lua contains a fairly small set of data structures. This page aims to document how much size each structure uses, to aid addon programmers with memory optimization.
This data is from WoW 2.0, Lua 5.1
Strings[edit]
Strings are allocated and garbage collected by the lua engine. Equal strings will not take up extra space (all strings are stored by reference). When a new string is allocated in memory, it will consume AT LEAST (17 + string length) bytes. However, strings are also tracked in a global hash table, which will grow as necessary, making the average memory consumption somewhere around 24+length bytes when the number of globally tracked strings grows.
Tables[edit]
Tables behave in different ways depending on how much data is put in them, and the style of indexing used.
A new, empty table will consume 40 bytes.
As indexes are added, the table will allocate space for new indexes at an exponential rate. For example:
local t = {} -- 40 bytes t[1] = true -- alloc 1 index t[2] = true -- alloc 1 index t[3] = true -- alloc 2 indexes t[4] = true t[5] = true -- alloc 4 indexes ...
If a table is indexed by sequential integers, each index will take 16 bytes (not including any memory allocated for the value). If the becomes a hash, the index size will jump to 40 bytes each. Lua is "smart" and will allocate at the 16 byte rate as much as it can. If the int sequence is broken, the new values will allocate at the 40 byte rate. For example:
local t = {} -- 40 bytes t[1] = true -- 16 bytes t[2] = true -- 16 bytes t[3] = true -- 32 bytes t[4] = true t[8] = true -- 40 bytes t[9] = true -- 40 bytes t[10] = true -- 80 bytes t["x"] = true t["y"] = true -- 160 bytes ...
Note that sequential-int and hash allocation can be intermixed. Lua will continue to allocate at the 16-byte rate as long as it possibly can.
local t = {} -- 40 bytes t[1] = true -- 16 bytes t["1"] = true -- 40 bytes t[2] = true -- 16 bytes t["2"] = true -- 40 bytes t[3] = true -- 32 bytes t["3"] = true -- 80 bytes
Erasing values from a table will not deallocate space used for indexes. Thus, tables don't "shrink back" when erased. However, if a value is written into the table on a new index, the table will deallocate back to fit it's new data. This is not delayed until a GC step, but rather an immediate effect. To erase and shrink a table, one can use:
for i,v in pairs(t) do t[i] = nil end t.reset = 1 t.reset = nil
- It should be noted that erasing a table is generally more expensive than collecting the table during GC. One may wish to simply allocate a new empty table.
Function closures[edit]
Note that the actual code also uses RAM, of course. But that only happens once. Closures however are created each time the word "function" is executed.
Each function closure takes 20 bytes of RAM. The below code will use 20000 bytes:
for t=1,1000 do
x = function() end
end
Upvalues that do not change only uses 4 bytes per closure. The below code will use 20000 + 4000 = 24000 bytes:
local semistatic = "hi!"
for t=1,1000 do
x = function() print(semistatic) end
end
However, upvalues that actually change use an additional 32 bytes. The below code will use 20000 + 4000 + 32000 = 56000 bytes:
for t=1,1000 do
x = function() print(t) end
end
And finally, a mix: The below code will use 20*2*500 + 4*2*500 + 32*500 = 40000 bytes
for t=1,500 do
for i=1,2 do
x = function() print(t) end
end
end