Lua metatable Objects cannot be cleared from memory?

I am using a proprietary platform that reported realtime memory usage on screen. I decided to use Class.lua which I found at http://lua-users.org/wiki/SimpleLuaClasses

However, I noticed memory issues when creating a cleanup object created with a simple Account class. Specifically, I would say, using 146k of used memory, create 1000 class objects that simply contain an integer instance variable and store each object in a table. The memory used is now 300K

Then I go out, iterate over the table and set each item in the table to zero. But 146k will never return, usually after that I am left using 210k or something similar. If I run the boot sequence again during the same session, it doesn't go over 300KB, so it's not a memory leak.

I tried to create 1000 integers in the table and set them to nil, which gives me 146k.

Also, I tried a simpler class file (Account2.lua) that doesn't rely on class.lua. This still causes memory fragmentation, but not as badly as the one using Class.lua

Can anyone explain what is going on here? How can I clear these objects and reclaim the memory?

here is the code -------- ------ 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.

      


- update I have updated the code with the suggestions from the comments below and will post my results later today.


- Update 2 Well I tried the above code and it looks like collectgarbage ("count") lua reports give me all memory in all 3 scenarios. Here are my results for collectgarbage ('count')

ACC0 - Early: 25.567K - Load: 89.334K - On Purge: 25.567K in use

ACC1 - At Start: 25.567K - At Load: 440.567k - On Purge: 25.567K Used

ACC2 - At the start: 25.327K - At boot: 245.34K - On Purge: 25.327K in use

+2


a source to share


3 answers


You need to force the garbage collector to reclaim memory (see collectgarbage("collect")

).



+2


a source


main.lua


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


      



According to the Lua documentation, you cannot reset table mappings by trying to set it to nil. It is just equal to the function getmetatable()

. This way the objects are preserved.

+1


a source


Most dynamic languages ​​don't actually release memory back to the system, but retain it for future allocations. Attempt to create some objects after Lua reported memory decline - Lua should use this free memory that it has kept for itself, and platform memory consumption will not increase.

+1


a source







All Articles