Memory 在Lua中,垃圾收集器可以确定地管理的对象/表的数量是否有限制?

Memory 在Lua中,垃圾收集器可以确定地管理的对象/表的数量是否有限制?,memory,memory-management,lua,garbage-collection,free,Memory,Memory Management,Lua,Garbage Collection,Free,为了便于参考,以下描述的场景是通过以下方式执行的: Ubuntu 18.04.4 LTS(仿生海狸) 顶部“procps ng 3.3.12” Lua 5.3.3版权所有(C)1994-2016 Lua.org,临市局里约 下面的每个“场景”演示了以下步骤的结果: 从“top”中捕获“lua5.3”初始流程资源使用情况 在“lua5.3”中,从堆中分配~16GB 从“top”中捕获“lua5.3”新进程资源使用情况,以显示已分配16GB 在“lua5.3”中,标记要删除的根对象,然后调用“c

为了便于参考,以下描述的场景是通过以下方式执行的:

  • Ubuntu 18.04.4 LTS(仿生海狸)
  • 顶部“procps ng 3.3.12”
  • Lua 5.3.3版权所有(C)1994-2016 Lua.org,临市局里约
下面的每个“场景”演示了以下步骤的结果:

  • 从“top”中捕获“lua5.3”初始流程资源使用情况
  • 在“lua5.3”中,从堆中分配~16GB
  • 从“top”中捕获“lua5.3”新进程资源使用情况,以显示已分配16GB
  • 在“lua5.3”中,标记要删除的根对象,然后调用“collectgarbage()
  • 从“顶部”捕获“lua5.3”最终进程资源使用情况,以显示“collectgarbage()的效果
  • 对于每个场景,比较初始进程资源使用情况、“已分配”进程资源使用情况以及“collectgarbage()后的最终进程资源使用情况。场景1显示“已分配”16GB在垃圾收集后不会释放。场景2和3显示一些“已分配”进程资源使用情况“16GB在垃圾回收后释放。场景4显示,所有“已分配”的16GB在垃圾收集后被释放。场景1到4仅在分配期间使用的对象(即表)数量上有所不同,其中场景1使用的表最多(128*1024),场景4使用的表最少(1)。因此,Lua 5.3.3垃圾收集似乎对其真正能够管理的对象数量有限制,或者Lua的内存管理存在缺陷

    简而言之,Lua的垃圾收集没有显示内存管理的确定性行为。如果创建了大量表,当Lua中不再需要内存时,与这些表关联的内存使用可能永远不会返回到由操作系统管理的堆中。但是,如果创建了少量的表,当Lua中不再需要内存时,与这些表相关联的内存使用似乎总是返回到由操作系统管理的堆中

    为什么Lua中的内存管理行为不一致/不确定

    注意:对于每个场景,在collectgarbage()之后调用collectgarbage(“count”)表示lua5.3已正确清理了所有垃圾,而使用“top”表示情况并非总是如此。因此,这里使用“top”来显示Lua垃圾收集的真实行为

    场景1:Lua collectgarbage()不释放使用的内存 场景2:Lua collectgarbage()释放所用内存的一半 场景3:Lua collectgarbage()释放几乎所有使用的内存 场景4:Lua collectgarbage()释放所有使用的内存 更新 经过额外的测试,Lua中管理的对象(即表)的数量似乎确实会影响Lua的垃圾收集行为。具体地说,如果Lua管理的表数少于256(这似乎是阈值),则在垃圾收集之后,内存将返回到操作系统的堆中。当对象的数量增长到256(含256)以上时,Lua的内存管理开始表现出不同的行为,因为它在垃圾收集后会保留更多内存供内部重用。上面的场景1显示了Lua在垃圾收集后对内存的影响最显著,场景4显示的影响最小

    注:示例结果不确定;也就是说,Lua中的其他执行可能会影响Lua的垃圾收集行为。为了获得最确定的结果,为每个测试启动一个新的Lua过程

    为了进行说明,以下示例连续分配、填充和取消分配一个表表,并从Lua过程中打印出以下内容:迭代、PremMemoryUsage(分配后)、PremMemoryUsagePercent、postMemoryUsage(取消分配后)、postMemoryUsagePercent

    示例程序:根据需要更改numberOfTables
    numberOfTables=255——示例1:255;例2:256
    函数getMemoryPercent()
    handle=io.popen(“v=`ps-p$PPID-opmem=|tr-d'\n'| sed's/*//g'`;echo-n$v”)
    memoryPercent=句柄:读(“*a”)
    句柄:close()
    返回存储器
    结束
    插座=需要(“插座”)
    打印(“#”、“预迁移”、“百分比”、“后迁移”、“百分比”)
    迭代=0
    虽然是真的
    做
    a={}
    对于i=1,numberOfTables
    做
    a[i]={}
    对于j=1,数学楼层(256*1024*1024/数字表格)
    做
    a[i][j]=i*j
    结束
    结束
    preMemoryUsage=collectgarbage(“计数”)
    preMemoryUsagePercent=getMemoryPercent()
    a=零
    收集垃圾()
    postMemoryUsage=收集垃圾(“计数”)
    postMemoryUsagePercent=getMemoryPercent()
    迭代=迭代+1
    打印(迭代、preMemoryUsage、preMemoryUsagePercent、postMemoryUsage、postMemoryUsagePercent)
    结束
    
    示例1:numberOfTables=255的结果 示例2:numberOfTables=256的结果
    可能,收集的内存可用于其他Lua对象,但尚未返回到操作系统。您可以使用双重调用
    collectgarbage()
    重复测试吗?您是否可以使用
    collectgarbage(“count”)
    重复测试,以获取内存使用情况,而不是执行
    top
    ?@EgorSkriptunoff I使用您请求的信息进行更新。重复调用collectgarbage()不会导致不同的行为。是的,起初我认为这是Lua“虚拟机”类型的行为,它允许Lua从操作系统获取内存,然后在内部管理内存。但后来我意识到使用“top”时,当我使用少量表时,这种行为是不同的。此外,当在C程序中使用Lua时,“C/Lua”进程的内存管理问题也是有问题的;Lua中使用的内存并不总是“释放”的,“C”部分可以“重用”内存。也许这不是Lua的错,因为Lua使用C库中的标准内存分配器。如果使用C堆,则应该看到相同的行为
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    22866 user      20   0   18152   3140   2840 S   0.0  0.0   0:00.00 lua5.3
    
    > collectgarbage("count")
    22.8759765625
    
    > a = {} for i=0,256*1024 do a[i] = {} for j=0,4*1024*1024 do a[i][j] = i*j end end
    
    > collectgarbage("count")
    16803927.791016
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    22866 user      20   0 16.053g 0.016t   2868 S   0.0 51.3   0:38.97 lua5.3
    
    > a = nil collectgarbage()
    
    > collectgarbage("count")
    25.29296875
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    22866 user      20   0 16.049g 0.016t   2868 S   0.0 51.3   0:39.08 lua5.3
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    22958 user      20   0   18152   3200   2916 S   0.0  0.0   0:00.00 lua5.3
    
    > collectgarbage("count")
    22.8759765625
    
    > a = {} for i=0,128*1024 do a[i] = {} for j=0,8*1024*1024 do a[i][j] = i*j end end
    
    > collectgarbage("count")
    16790679.791016
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    22958 user      20   0 16.284g 0.016t   2944 S   0.0 52.0   0:39.79 lua5.3
    
    > a = nil collectgarbage()
    
    > collectgarbage("count")
    23.1826171875
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    22958 user      20   0 8422324 8.018g   2944 S   0.0 25.6   0:40.50 lua5.3
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    23127 user      20   0   18152   3192   2904 S   0.0  0.0   0:00.00 lua5.3
    
    > collectgarbage("count")
    22.8759765625
    
    > a = {} for i=0,64*1024 do a[i] = {} for j=0,16*1024*1024 do a[i][j] = i*j end end
    
    > collectgarbage("count")
    16784151.791016
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    23127 user      20   0 16.275g 0.016t   2932 S   0.0 52.0   0:41.22 lua5.3
    
    > a = nil collectgarbage()
    
    > collectgarbage("count")
    23.1826171875
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    23127 user      20   0   25900  10992   2932 S   0.0  0.0   0:41.81 lua5.3
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    23771 user      20   0   18152   3204   2920 S   0.0  0.0   0:00.00 lua5.3
    
    > collectgarbage("count")
    22.8759765625
    
    > a = {} for i=0,0 do a[i] = {} for j=0,1024*1024*1024 do a[i][j] = i*j end end
    
    > collectgarbage("count")
    16777241.969727
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    23771 user      20   0 16.017g 0.016t   2948 S   0.0 51.2   0:38.97 lua5.3
    
    > a = nil collectgarbage()
    
    > collectgarbage("count")
    23.17578125
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    23771 user      20   0   18152   3364   2948 S   0.0  0.0   0:40.80 lua5.3
    
    #       preMemUsage     %       postMemUsage     %
    1       8355905.0869141 25.4    47.240234375     0.0
    2       8355905.1972656 25.4    47.322265625     0.0
    3       8355905.1972656 25.4    47.322265625     0.0
    4       8355905.1972656 25.4    47.322265625     0.0
    5       8355905.1972656 25.4    47.322265625     0.0
    6       8355905.1972656 25.4    47.322265625     0.0
    7       8355905.1972656 25.4    47.322265625     0.0
    8       8355905.1972656 25.4    47.322265625     0.0
    9       8355905.1972656 25.4    47.322265625     0.0
    10      8355905.1972656 25.4    47.322265625     0.0
    
    #       preMemUsage     %       postMemUsage     %
    1       4194369.0205078 12.8    47.119140625     0.0
    2       4194369.1308594 12.8    47.201171875     12.8
    3       4194369.1035156 12.8    47.173828125     12.5
    4       4194369.1318359 12.8    47.2021484375    12.4
    5       4194369.1318359 12.8    47.2021484375    12.4
    6       4194369.1318359 12.8    47.2021484375    12.4
    7       4194369.1318359 12.8    47.2021484375    12.4
    8       4194369.1318359 12.8    47.2021484375    12.4
    9       4194369.1318359 12.8    47.2021484375    12.4
    10      4194369.1318359 12.8    47.2021484375    12.4