Как современные виртуальные машины справляются с выделением памяти?


Я работаю над простой стековой машиной, написанной на языке Си, в основном для учебных целей. После использования malloc/free для операций с памятью я подумал, что было бы неплохо прочитать определенный код выделения памяти из современных виртуальных машин.

Я скачал исходный код Lua и начал его читать. Через некоторое время я понял, что есть много макросов, связанных с этим, и я не мог найти код, в котором выполняется реальное выделение памяти (т. е. malloc Звонок).
find . -exec grep -i "malloc" '{}' ; -print

Он напечатал только некоторые Lua макросы, которые имеют malloc слово в своих именах. Lua VM (и язык программирования) вообще не использует malloc!

Это подводит меня к вопросу: как современные виртуальные машины справляются с распределением памяти? Как Lua выделяет память из кучи? Существуют ли другие способы распределения, кроме malloc? Каковы плюсы / минусы других методов?

Я также интересуюсь лучшими практиками, моделями дизайна и т. д. для безопасной работы с выделенной памятью. Я вижу в источнике Луа, что есть много косвенное обращение перед выделением памяти. Где я могу узнать об этом?

2 16

2 ответа:

Lua наиболее определенно использует malloc в форме realloc (можно также передать пользовательский распределитель), однако, поскольку Lua использует GC, как 99% языков на основе виртуальных машин, он использует макросы для автоматического добавления блока заголовка GC к распределению.

Вы найдете память Lua, обрабатываемую всеми подпрограммами LuaM_ в lmem.c и lmem.h, все они используют глобальное состояние виртуальной машины для хранения распределителя, который изначально установлен в l_alloc (из lauxlib.c), но может быть изменен с помощью lua_setallocf.

Недавно LuaJIT добавил понижение выделения и планы для некоторых действительно интересных функций памяти, которые вы можете прочитать в этой статье о сборке мусора LuaJIT. В статье рассматривается множество стратегий и проектов, связанных с выделением памяти VM/JIT, потоплением, агрегированием и сбором мусора.

Как вы можете видеть, стратегии выделения памяти и погружения очень тесно связаны с GC, который используется (если таковые имеются).

В терминах " за " и "против" из различные распределители памяти , использующие стандартные malloc, просты в использовании, но за счет скорости и потерь на выравнивание и различных дополнительных блоков, помеченных на каждом выделении.

Переходя к более продвинутым распределителям arena, pool, slab и block, мы можем значительно ускорить процесс (особенно для внутренних распределений VM фиксированного размера) и избежать значительной фрагментации и накладных расходов, которые могут возникнуть с более общими распределителями, такими как malloc, но, конечно, эти распределители более эффективны. сложные, и вы должны отлаживать их, если вы начинаете с нуля (что в более крупной системе, такой как виртуальная машина, просто требует проблем), как приложено к испытанной реализации CRT malloc.

Ядро Lua не использует malloc и друзей. Он опирается на предоставленную пользователем функцию выделения памяти, которая имеет realloc-подобную семантику (но более точна при обработке NULL указателей и размеров 0). Смотрите lua_Alloc .

Вспомогательная библиотека Lua предоставляет функцию удобства luaL_newstate, которая создает состояние Lua через функцию ядра lua_newstate, используя функцию выделения памяти, основанную на стандартных realloc и free. Другие клиенты могут использовать любое распределение памяти, подходящее для их приложение.