Page 1 of 1

Table memory layout

Posted: Thu Feb 06, 2025 9:44 pm
by Urigald
Hello,

I'm beginning to code my game ECS (I know, how original), and for the way I intend to code it, I have a question about the tables memory layout so as to minimize cache miss occurences.

I have read a bit about table memory layout, but It's difficult to understand for my tiny brain, so please bear with me.
If I get it correctly, tables have two distinct part, an array-like part, and a hash-map part, depending on what data is stored inside them ( = how we use them, pure array or associative array), and for the first part, array, memory should be contiguous right ? But the second part, the hash map, is not.

So, what about a table like so :

Code: Select all

 mytable[array_1] = {2, 3, 5, 6, 8, 9}
mytable[array_2] = {6, 13, 25, 96, 78, 49} 
Since the values are arrays, is the memory of each of these arrays contiguous as well ? I'm not asking if array_2 is contiguous to array_1, that I guess it is not. But {2, 3, 5, 6, 8, 9} should be, as well as {6, 13, 25, 96, 78, 49}....right ?

Thank you for the help, sorry for my english.

EDIT : btw, I have read these topics, and found bits of info.
viewtopic.php?t=82902
viewtopic.php?t=86843
viewtopic.php?t=84361
I will not use ffi ; the GBC can fragment initially contiguous memory ? If I remove 25, will it still be contiguous then ?

Re: Table memory layout

Posted: Fri Feb 07, 2025 6:49 am
by dusoft
No offense, but you are bit overthinking. Premature optimization is ... etc. etc.

Re: Table memory layout

Posted: Fri Feb 07, 2025 8:08 am
by darkfrei
Make the script for making 256, 512, 1024, 2048... tables and write to console each iteration. After a wile you can get the highest amount of them. It's over a million!

Re: Table memory layout

Posted: Fri Feb 07, 2025 12:43 pm
by pgimeno
Urigald wrote: Thu Feb 06, 2025 9:44 pm So, what about a table like so :

Code: Select all

 mytable[array_1] = {2, 3, 5, 6, 8, 9}
mytable[array_2] = {6, 13, 25, 96, 78, 49} 
Since the values are arrays, is the memory of each of these arrays contiguous as well ? I'm not asking if array_2 is contiguous to array_1, that I guess it is not. But {2, 3, 5, 6, 8, 9} should be, as well as {6, 13, 25, 96, 78, 49}....right ?
Right.
Urigald wrote: Thu Feb 06, 2025 9:44 pm If I remove 25, will it still be contiguous then ?
Generally, yes. The space is already allocated and won't be freed. If you remove it by setting the value for its index to nil, then the length operator # will return the full length, which is a hint that the space is still reserved. But these behaviours are undefined so it's not guaranteed to be true for future versions. Also, be careful because ipairs() will stop at the first nil.

You can also remove it in three other ways that are well defined. One is not really removing it, but invalidating it: you set its index to, say, 0 (or false) instead of 25. The second one is with table.remove, but that's an O(n) operation, not O(1), and will change the index of all elements starting with that one, which may or may not be adequate.

The third way is adequate if you don't care about the order of the elements: move the last one to the one you want to remove, then set the last one to nil.

Here are examples of all these ways:

Code: Select all

t = {6, 13, 25, 96, 78, 49}

-- Method 1: set to nil
t[3] = nil
print(#t)  -- prints 6, hinting that the memory for the array part is still reserved
-- now the table is {6, 13, nil, 96, 78, 49}

-- Method 2a: set to 0
t[3] = 0
-- now the table is {6, 13, 0, 96, 78, 49}

-- Method 2b: set to false
t[3] = false
-- now the table is {6, 13, false, 96, 78, 49}
-- note however that the JIT works better if the types are uniform,
-- so 2a is preferable

-- Method 3: table.remove
table.remove(t, 3)
-- Now the table is {6, 13, 96, 78, 49}

-- Method 4: Replace with the last element  then remove last element
t[3] = t[#t]
t[#t] = nil
-- Now the table is {6, 13, 49, 96, 78}
-- This is the best method if order isn't important.

Re: Table memory layout

Posted: Sat Feb 08, 2025 12:20 pm
by RNavega
Also note the LuaJIT extension to pre-allocate a table:
https://luajit.org/extensions.html#table_new

(LÖVE uses LuaJIT as the interpreter, so you have access to that and the other extensions.)