Lua metatable Objects无法从内存中清除?

时间:2010-04-28 21:58:30

标签: lua oop memory-management

我正在使用专有平台,在屏幕上实时报告内存使用情况。我决定使用我在http://lua-users.org/wiki/SimpleLuaClasses

上找到的Class.lua

但是,我注意到使用简单的Account类清除由此创建的对象时的内存问题。具体来说,我首先要说使用146k的内存,创建一个只包含整数实例变量的类的1000个对象,并将每个对象存储到一个表中。 使用的内存现在是300k

然后我会退出,遍历表并将表中的每个元素设置为nil。但是永远不会得到146k,通常在此之后我会使用210k或类似的东西。如果我在同一个会话期间再次运行加载序列,它不会超过300k,因此它不是内存泄漏。

我尝试在表格中创建1000个整数并将它们设置为nil,这确实给了我146k。

此外,我尝试了一个不依赖于class.lua的简单类文件(Account2.lua)。这仍然会导致内存碎片,但不会像使用Class.lua

那样多

有人可以解释这里发生了什么吗?如何清除这些物体并取回记忆?

这是代码 -------- Class.lua ------


-- class.lua
-- Compatible with Lua 5.1 (not 5.0).
--http://lua-users.org/wiki/SimpleLuaClasses
function class(base,ctor)
  local c = {}     -- a new class instance
  if not ctor and type(base) == 'function' then
      ctor = base
      base = nil
  elseif type(base) == 'table' then
   -- our new class is a shallow copy of the base class!
      for i,v in pairs(base) do
          c[i] = v
      end
      c._base = base
  end
  -- the class will be the metatable for all its objects,
  -- and they will look up their methods in it.
  c.__index = c

  -- expose a ctor which can be called by ()
  local mt = {}
  mt.__call = function(class_tbl,...)
    local obj = {}
    setmetatable(obj,c)
    if ctor then
       ctor(obj,...)
    else 
    -- make sure that any stuff from the base class is initialized!
       if base and base.init then
         base.init(obj,...)
       end
    end
    return obj
  end
  c.init = ctor
  c.instanceOf = function(self,klass)
      local m = getmetatable(self)
      while m do 
         if m == klass then return true end
         m = m._base
      end
      return false
    end
  setmetatable(c,mt)
  return c
end

-------- Account.lua ------


--Import Class template
require 'class'
local classname = "Account" 
    --Declare class Constructor
    Account = class(function(acc,balance)
    --Instance variables declared here.
         if(balance ~= nil)then
                     acc.balance = balance
                    else
                     --default value
                     acc.balance = 2097
                    end
                    acc.classname = classname
                 end)

-------- Account2.lua ------


local account2 = {}

account2.classname  = "unnamed"
account2.balance  = 2097

-----------Constructor 1
do
 local metatable = {
  __index = account2;
 }

 function Account2()
  return setmetatable({}, metatable);
 end
end

-------- Main.lua ------


require 'Account'
require 'Account2'

MAX_OBJ    = 5000;
test_value = 1000;
Obj_Table = {};
MODE_ACC0 = 0 --integers
MODE_ACC1 = 1 --Account
MODE_ACC2 = 2 --Account2
TEST_MODE = MODE_ACC0;

Lua_mem = 0;

function Load()
 for i=1, MAX_OBJ do
    if(TEST_MODE == MODE_ACC0 )then
        table.insert(Obj_Table, test_value);

    elseif(TEST_MODE == MODE_ACC1 )then
         table.insert(Obj_Table, Account(test_value)); --Account.lua

    elseif(TEST_MODE == MODE_ACC2 )then
         table.insert(Obj_Table, Account2()); --Account2.lua
        Obj_Table[i].balance = test_value;
    end
 end
end

function Purge()
    --metatable purge
    if(TEST_MODE ~= MODE_ACC0)then
      --purge stage 0: 
      print("set each elements metatable to nil")
      for i=1, MAX_OBJ do
        setmetatable(Obj_Table[i], nil);
      end
    end 

    --purge stage 1: 
    print("set table element to nil")
    for i=1, MAX_OBJ do
      Obj_Table[i] = nil;
    end 

    --purge stage 2: 
    print("start table.remove...");
    for i=1, MAX_OBJ do
    table.remove(Obj_Table, i);
    end 
    print("...end table.remove");

    --purge stage 3: 
    print("create new object_table {}");
    Obj_Table= {};

    --purge stage 4: 
    print("collectgarbage('collect')");
    collectgarbage('collect');


end

--Loop callback, called every tick
function OnUpdate()
   Lua_mem = collectgarbage('count');
   collectgarbage('collect');
end
--Loop rendering callback

function OnRender()
   DrawText(Lua_mem );
end
-------------------
--NOTE:
--code starts in idle awaiting input from user
--On first input, runs Load(), on exit runs Purge()
--Where DrawText() draws the string parameter passed, to screen.

- 更新 我已根据以下评论中的建议更新了代码,并将在今天晚些时候发布我的调查结果。


- 更新2 好吧,我已经尝试了上面的代码,它看起来似乎收集垃圾(“计数”)报告lua给了我所有三种情况下的所有内存。 以下是我对collectgarbage('count')的结果

ACC0   - 开始时:使用25.567K   - 在负载时:使用89.334K   - 关于清除:使用25.567K

ACC1   - 开始时:使用25.567K   - 负载:使用440.567k   - 关于清除:使用25.567K

ACC2   - 开始时:使用25.327K   - 负载:使用245.34K   - 关于清除:使用25.327K

3 个答案:

答案 0 :(得分:2)

您需要强制垃圾收集器回收内存(请参阅collectgarbage("collect"))。

答案 1 :(得分:1)

<强> Main.lua


    --purge stage 0: 
    print("set each elements metatable to nil")
    for i=1, MAX_OBJ do
        setmetatable(Obj_Table[i], nil);
    end

根据documentation of Lua,您无法通过尝试将其设置为nil来重置表metatable。它只等于函数getmetatable()。因此,对象不断被链接。

答案 2 :(得分:1)

大多数动态语言并没有真正将内存释放回系统,而是为将来的分配做好准备。在Lua报告内存减少后尝试创建一些对象 - Lua应该使用它保留给自己的这个释放的内存,平台内存消耗不会增加。