Создает ли toluapp утечку памяти при использовании tolua_pushusertype_and_takeownership?

Этот вопрос может быть для экспертов Lua и Tolua.

Я использую tolua ++ 1.0.93 и lua-5.1.4 (зависимости CEGUI 0.84).
Я отслеживал эту неприятную утечку памяти в течение нескольких часов и обнаружил, что toluapp создает таблицу tolua_gc в реестре Lua, и кажется, что эта таблица растет бесконечно.

Когда я перемещаю свой объект в Lua с помощью tolua_pushusertype_and_takeownership, я хочу, чтобы Lua GC удалил мой объект. И это так, но tolua_pushusertype_and_takeownership вызывает tolua_register_gc, который помещает эти объекты метатизируемыми под объект в качестве ключа к этой «глобальной» таблице tolua_gc.
Когда функция tolua_gc_event вызывает функцию сборщика (которая вызывает оператор удаления), она устанавливает значение nil в таблицу tolua_gc для только что удаленного объекта в качестве ключа. Так что должно работать, верно?

Ну нет.

Может быть, я что-то не так понял, но, похоже, это никак не влияет на размер таблицы tolua_gc.
Я также пытался вручную вызвать tolua.releaseownership (объект) из Lua. И это сработало. Я имею в виду, что он уменьшил объем памяти, используемой Lua (LUA_GCCOUNT), но, поскольку он отключил сборщик от объекта, оператор delete никогда не вызывался, и это вызывало утечки памяти в C ++.

Это действительно странное поведение, потому что все, что делает tolua.releaseownership, это устанавливает значение nil в таблицу tolua_gc под переданным объектом в качестве ключа.
Так почему же tolua.releaseownership уменьшает размер памяти, используемой Lua, а tolua_gc_event нет?
Единственное отличие состоит в том, что tolua.releaseownership вызывает сборщик мусора до того, как он установит nil в таблицу tolua_gc, а сборщик мусора вызывает tolua_gc_event (противоположная ситуация).

Зачем нам нужна эта глобальная таблица tolua_gc? Разве мы не можем просто взять метатабельный объект непосредственно в момент сбора?

У меня действительно ограниченная память, которую я могу использовать из этого процесса (8 МБ), и кажется, что эта таблица tolua_gc занимает около 90% ее через некоторое время.

Как я могу это исправить?

Спасибо.

РЕДАКТИРОВАТЬ:
Это примеры кода:

extern unsigned int TestSSCount;

class TestSS
{
public:
double d_double;

TestSS()
{
//        TestSSCount++;
//        fprintf(stderr, "c(%d)\n",TestSSCount);
}

TestSS(const TestSS& other)
{
d_double = other.d_double * 0.5;
//        TestSSCount++;
//        fprintf(stderr, "cc(%d)\n",TestSSCount);

}

~TestSS()
{
//        TestSSCount--;
//        fprintf(stderr, "d(%d)\n", TestSSCount);
}
};class App
{
...
TestSS doNothing()
{
TestSS t;
t.d_double = 13.89;
return t;
}

void callGC()
{
int kbs_before = lua_gc(d_state, LUA_GCCOUNT, 0);
lua_gc(d_state, LUA_GCCOLLECT, 0);
int kbs_after = lua_gc(d_state, LUA_GCCOUNT, 0);
printf("GC changed memory usage from %d kB to %d kB, difference %d kB",
kbs_before, kbs_after, kbs_before - kbs_after);
}

...
};

Это файл .pkg:

class TestSS
{
public:
double d_double;
};

class App
{
TestSS doNothing();
void callGC();
};

Теперь завершите код Lua (app и rootWindow являются объектами C ++, предоставленными как константы Lua):

function handleCharacterKey(e_)
local key = CEGUI.toKeyEventArgs(e_).scancode

if key == CEGUI.Key.One then
for i = 1,10000,1 do
-- this makes GC clear all memory from Lua heap but does not call destructor in C++
-- tolua.releaseownership(app:doNothing())
-- this makes GC call destructors in C++ but somehow makes Lua heap increase constantly
app:doNothing()
elseif key == CEGUI.Key.Zero then
app:callGC()
end
end

rootWindow:subscribeEvent("KeyUp", "handleCharacterKey")

Это вывод, который я получаю при нажатии 0 1 0 1 0 1 0:

Это когда я использую tolua.releaseowenership

GC changed memory usage from 294 kB to 228 kB, difference 66 k
GC changed memory usage from 228 kB to 228 kB, difference 0 kB
GC changed memory usage from 228 kB to 228 kB, difference 0 kB
GC changed memory usage from 228 kB to 228 kB, difference 0 kB

Это без толуа.

GC changed memory usage from 294 kB to 228 kB, difference 66 kB
GC changed memory usage from 605 kB to 604 kB, difference 1 kB
GC changed memory usage from 982 kB to 861 kB, difference 121 kB
GC changed memory usage from 1142 kB to 1141 kB, difference 1 kB

И это без права владения релизом, но последовательность, которую я нажимаю на клавиатуре, равна 0 1 0 1 0 1 0 0 0 0 (еще три дополнительных звонка в GC в конце)

GC changed memory usage from 294 kB to 228 kB, difference 66 kB
GC changed memory usage from 603 kB to 602 kB, difference 1 kB
GC changed memory usage from 982 kB to 871 kB, difference 111 kB
GC changed memory usage from 1142 kB to 1141 kB, difference 1 kB
GC changed memory usage from 1141 kB to 868 kB, difference 273 kB <- this is after first additional GC call
GC changed memory usage from 868 kB to 868 kB, difference 0 kB
GC changed memory usage from 868 kB to 868 kB, difference 0 kB

0

Решение

Проблема не в ошибке или утечке памяти. Хотя вы могли бы сказать, что это утечка памяти, если у вас действительно ограниченная память. Проблема в том, что tolua_gc, будучи таблицей lua, не перефразирует, когда вы удаляете элементы, устанавливая их в ноль.

Хотя я и предполагал, что это может быть проблемой, я был достаточно глуп, чтобы не видеть, правда ли это. Поэтому сборщик мусора не может заставить таблицу перефразировать и уменьшить ее размер. Таким образом, таблица будет расти до определенной вставки, которая вызовет перефразировку.
Прочитай это: http://www.lua.org/gems/sample.pdf

Итак, в конце я удалил таблицу tolua_gc и поместил метатаблицы (которые tolua использовал для помещения таблицы tolua_gc с ключом lightuserdata) в качестве специального поля в самом объекте userdata.
И также вместо того, чтобы обращаться к этим метатаблицам из таблицы tolua_gc, я получаю их сейчас из самого объекта. Все остальное тоже самое, и похоже на работу.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]