在之前的重新散列之后强制表重新运行不起作用

时间:2016-04-21 09:28:23

标签: lua garbage-collection

我创建了一个调整数组大小并将新条目设置为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>

我错过了什么吗?我期待第三个人在第二个人之后也会重新开始。

1 个答案:

答案 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

以下是发生的事情:

  • 在调整大小为50000个元素的过程中,表重新进行了几次,最后它只包含n字段的一个散列部分插槽和足够的整数键的数组部分插槽。
  • 在缩小到10000个元素的过程中,首先将nil分配给整数键10001到65536,然后分配到65537到100000.第一组分配将从不导致重新分组,因为您分配给现有字段。这与guarantees for the next function有关。第二组赋值将导致重新进行,但由于你正在分析nil,所以Lua会在某些时候意识到表的数组部分是空的半空(参见{{3}开头的注释) })。然后Lua将数组部分缩小到合理的大小,并为新密钥使用第二个哈希槽。但是,由于您要分配nil s,第二个散列槽永远不会被占用,并且Lua可以自由地重新使用它来所有剩余的分配(并且它经常但并非总是如此) 。此时你不会注意到rehash,因为你总是会得到16384个数组插槽和2个散列槽(一个用于n,一个用于分配新元素。)
  • 缩小到20个元素只是继续这种方式,除了第二个哈希槽已经可用。所以你可能从不得到一个rehash(并且数组大小仍然大于必要),但如果你(Lua由于某种原因并不喜欢那个免费的那个)哈希插槽),您将看到阵列插槽的数量下降到合理的水平。

当你在第二次缩小期间进行重组时,这就是它的样子:

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)现在也会返回表格数组/散列部分中的插槽数。

相关问题