Lua 表在内存中是如何处理的?

How are Lua tables handled in memory?

lua 如何处理 table 的增长?

是否等同于Java中的ArrayList? IE。一个需要连续内存 space,并且随着它的增长大于已经分配的 space,内部数组被复制到另一个内存 space.

有没有聪明的方法来引导它?

我的问题是,一个table是如何存储在内存中的?我不是在问如何在 Lua.

中实现数组

自 Lua 5.0 起,table 是散列 table 和数组的混合体。来自 The Implementation of Lua 5.0:

New algorithm for optimizing tables used as arrays:

Unlike other scripting languages, Lua does not offer an array type. Instead, Lua programmers use regular tables with integer indices to implement arrays. Lua 5.0 uses a new algorithm that detects whether tables are being used as arrays and automatically stores the values associated to numeric indices in an actual array, instead of adding them to the hash table. This algorithm is discussed in Section 4.

之前的版本只有哈希 table.

(假设您指的是 Lua 的最新版本;描述 5.3 的行为应该(几乎?)与 5.0-5.2 相同。)

在幕后,table 包含一个数组和一个散列部分。两者都(独立地)以二次方的形式增长和收缩,如果不需要,两者都可以不存在。

大多数键值对将存储在哈希部分。但是,所有正整数键(从 1 开始)都是存储在数组部分的候选者。数组部分只存储值而不存储键(因为它们等同于数组中元素的位置)。分配的 space 的最多一半允许为空(即包含 nil——作为间隙或尾随空闲槽)。 (会留下太多空槽的候选数组将被放入散列部分。如果数组部分已满但散列部分中有剩余 space,则任何条目都将进入散列部分。)

对于数组和散列部分,插入都可以触发调整大小,如果之前删除了足够多的条目,则可以调整到下一个更大的 2 的幂,或者向下调整到 2 的任何更小的幂。 (实际上,触发缩小尺寸并非易事:rehash is the only place where a table is resized (and both parts are resized at the same time), and it is only called from luaH_newkey if 两个部分中的任何一个都不够 space1 .)

有关更多信息,您可以查看 The Implementation of Lua 5.0, or inspect the source: Basically everything of relevance happens in ltable.c, interesting starting points for reading are rehash (in ltable.c) (the resizing function), and the main interpreter loop luaV_execute (in lvm.c) or more specifically luaV_settable (also there) 的第 4 章(在 table 中存储键值对时会发生什么)。


1例如,为了缩小 table 包含一个大数组部分但没有散列,你必须清除所有数组条目,然后向散列部分添加一个条目(即使用非整数键,该值可以是任何 包括 nil),最终得到一个table 不包含数组部分和 1 元素散列部分。
如果两个部分都包含条目,则必须首先清除散列部分,然后向数组部分添加足够的条目以填充数组和散列的组合(以触发调整大小,这将使 table 带有大数组部分,没有散列),然后如上所述清除数组。2(首先清除数组然后散列将不起作用,因为在清除两个部分后你将没有数组和一个巨大的散列部分,并且您无法触发调整大小,因为任何条目都会进入散列。)

2实际上,扔掉 table 并制作一个新的 很多 更容易一。为确保缩减 table,您需要知道实际分配的容量( 不是 当前条目数,Lua不会告诉你,至少不会直接告诉你),然后让所有的步骤和所有的大小都恰到好处——混淆步骤的顺序或者无法触发调整大小,你最终会得到一个巨大的 table 如果你将它用作数组,它甚至可能执行得更慢......(存储在哈希中的候选数组也存储它们的键,例如缓存行中有用数据量的一半。)