Lua Metatable Objects нельзя вычеркнуть из памяти? - PullRequest
2 голосов
/ 29 апреля 2010

Я использую проприетарную платформу, которая сообщает об использовании памяти в режиме реального времени на экране. Я решил использовать Class.lua, найденный на http://lua -users.org / wiki / SimpleLuaClasses

Однако я заметил проблемы с памятью при очистке объекта, созданного с помощью простого класса Account. В частности, я хотел бы начать с, скажем, 146 КБ используемой памяти, создать 1000 объектов класса, который просто содержит целочисленную переменную экземпляра и сохранить каждый объект в таблицу. Используемая память теперь 300k

Затем я бы завершил работу, перебирая таблицу и устанавливая для каждого элемента таблицы значение nil. Но никогда не получу обратно 146k, обычно после этого я оставляю 210k или что-то подобное. Если я выполню последовательность загрузки еще раз во время того же сеанса, она не превысит 300 Кбайт, поэтому это не утечка памяти.

Я попытался создать 1000 целых чисел в таблице и установить их равными nil, что возвращает мне 146 тыс.

Кроме того, я попробовал более простой файл класса (Account2.lua), который не зависит от class.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 Ну, я попробовал приведенный выше код, и кажется, что сборщик мусора ("count") сообщает, что lua возвращает мне всю память во всех трех сценариях. Вот мои результаты для collectgarbage ('count')

ACC0 - На старте: 25,567K используется - На нагрузке: 89,334K используется - При продувке: 25,567K используется

ACC1 - На старте: 25,567K используется - На нагрузке: 440,567 Кб - При продувке: 25,567K используется

ACC2 - На старте: 25,327K используется - На нагрузке: 245,34K используется - При продувке: 25,327K используется

Ответы [ 3 ]

2 голосов
/ 29 апреля 2010

Необходимо заставить сборщик мусора вернуть память (см. collectgarbage("collect")).

1 голос
/ 04 ноября 2012

Большинство динамических языков на самом деле не освобождают память обратно в систему, но вместо этого держат ее наготове для будущих распределений. Попробуйте создать несколько объектов после того, как Lua сообщит об уменьшении памяти - Lua следует использовать эту освобожденную память, которую она сохранила для себя, и потребление памяти платформой не увеличится.

1 голос
/ 04 ноября 2012

main.lua


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

В соответствии с документацией Lua вы не можете сбросить метатабильную таблицу, пытаясь установить ее в ноль. Это просто равно функции getmetatable(). Таким образом, объекты продолжают быть связанными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...