我创建了一个调整数组大小并将新条目设置为0的函数,但也可以通过两种不同的方式减小数组的大小:
1.只需将n
属性设置为新大小(由于这个原因,不能使用长度运算符)。
2.将新尺寸后的所有值设置为nil,最大为2 *,以强制重新散列。
local function resize(array, elements, free)
local size = array.n
if elements < size then -- Decrease Size
array.n = elements
if free then
size = math.max(size, #array) -- In case of multiple resizes
local base = elements + 1
for idx = base, 2*size do -- Force a rehash -> free extra unneeded memory
array[idx] = nil
end
end
elseif elements > size then -- Increase Size
array.n = elements
for idx = size + 1, elements do
array[idx] = 0
end
end
end
我是如何测试的:
local mem = {n=0};
resize(mem, 50000)
print(mem.n, #mem) -- 50000 50000
print(collectgarbage("count")) -- relatively large number
resize(mem, 10000, true)
print(mem.n, #mem) -- 10000 10000
print(collectgarbage("count")) -- smaller number
resize(mem, 20, true)
print(mem.n, #mem) -- 20 20
print(collectgarbage("count")) -- same number as above, but it should be a smaller number
然而,当我没有将true
作为第二个调用大小调整传递给第二个调用时(因此它不会强制重新调整第二个调用),第三个调用最终会重新调整它。 / p>
我错过了什么吗?我期待第三个人在第二个人之后也会重新开始。
答案 0 :(得分:4)
以下是关于调整大小之前和之后表格通常如何显示的更清晰的图片:
table: 0x15bd3d0 n: 0 #: 0 narr: 0 nrec: 1
table: 0x15bd3d0 n: 50000 #: 50000 narr: 65536 nrec: 1
table: 0x15bd3d0 n: 10000 #: 10000 narr: 16384 nrec: 2
table: 0x15bd3d0 n: 20 #: 20 narr: 16384 nrec: 2
以下是发生的事情:
n
字段的一个散列部分插槽和足够的整数键的数组部分插槽。nil
分配给整数键10001到65536,然后分配到65537到100000.第一组分配将从不导致重新分组,因为您分配给现有字段。这与guarantees for the next
function有关。第二组赋值将导致重新进行,但由于你正在分析nil
,所以Lua会在某些时候意识到表的数组部分是空的半空(参见{{3}开头的注释) })。然后Lua将数组部分缩小到合理的大小,并为新密钥使用第二个哈希槽。但是,由于您要分配nil
s,第二个散列槽永远不会被占用,并且Lua可以自由地重新使用它来所有剩余的分配(并且它经常但并非总是如此) 。此时你不会注意到rehash,因为你总是会得到16384个数组插槽和2个散列槽(一个用于n
,一个用于分配新元素。)当你做在第二次缩小期间进行重组时,这就是它的样子:
table: 0x11c43d0 n: 0 #: 0 narr: 0 nrec: 1
table: 0x11c43d0 n: 50000 #: 50000 narr: 65536 nrec: 1
table: 0x11c43d0 n: 10000 #: 10000 narr: 16384 nrec: 2
table: 0x11c43d0 n: 20 #: 20 narr: 32 nrec: 2
如果你想重复我的实验,git HEAD版本的ltable.c
(原始版本lua-getsize
)现在也会返回表格数组/散列部分中的插槽数。