На 64-битных платформах LuaJIT разрешает только до 1-2 ГБ данных (не считая объектов, выделенных с помощью malloc
). Откуда это ограничение и почему оно даже меньше, чем на 32-битных платформах?
Почему память LuaJIT ограничена 1-2 ГБ на 64-битных платформах?
Ответы (2)
LuaJIT предназначен для использования 32-битных указателей. На x64
платформах ограничение возникает из-за использования mmap и флага MAP_32BIT
.
MAP_32BIT (начиная с Linux 2.4.20, 2.6):
Поместите сопоставление в первые 2 гигабайта адресного пространства процесса. Этот флаг поддерживается только на x86-64 для 64-битных программ. Он был добавлен, чтобы позволить размещать стеки потоков где-то в первых 2 ГБ памяти, чтобы повысить производительность переключения контекста на некоторых ранних 64-разрядных процессорах.
По сути, использование этого флага ограничивает первые 31 бит, а не первые 32 бита, как следует из названия. Посмотрите здесь за хороший обзор ограничения в 1 ГБ с использованием MAP_32BIT
в ядре Linux.
Даже если бы у вас было больше 1 ГБ, автор LuaJIT объясняет, почему это плохо скажется на производительности:
- Полный сборщик мусора занимает на 50 % больше времени, чем сами выделения.
- Если GC включен, он удваивает время выделения.
- Для имитации реального приложения связи между объектами рандомизируются в третьем прогоне. Это удваивает время GC!
И это всего за 1 Гб! А теперь представьте, что вы используете 8 ГБ — полный цикл GC загрузит ЦП целых 24 секунды! Итак, нормальный режим — использовать инкрементный сборщик мусора. Но это просто означает, что накладные расходы на ~ 30% выше, они смешаны между распределениями и каждый раз будут вытеснять кэш ЦП. По сути, в вашем приложении будут преобладать накладные расходы сборщика мусора, и вы начнете задаваться вопросом, почему он работает медленно....
tl;dr версия: не пытайтесь повторить это дома. И GC нуждается в перезаписи (перенесено на LuaJIT 2.1).
Подводя итог, ограничение в 1 ГБ — это ограничение ядра Linux и сборщика мусора LuaJIT. Это относится только к объектам в состоянии LuaJIT и может быть преодолено с помощью malloc
, который будет выделяться за пределами нижнего 32-битного адресного пространства. Кроме того, можно использовать сборку x86
на x64
в 32-битном режиме и иметь доступ ко всем 4 ГБ.
Проверьте эти ссылки для получения дополнительной информации:
- Как пройти 1 ГБ памяти ограничение 64-битного LuaJIT в Linux?
- LuaJIT x64 ограничено 31-битным адресным пространством, даже без ограничений MAP_32BIT?
- странный лимит памяти LuaJIT
- Выявление самой сумасшедшей ошибки, которую вы никогда не слышал о 2008 году: регресс потоков в Linux
Из-за недавнего патча luajit 2 ГБ памяти предел можно решить.
Для тестирования клонируйте этот репозиторий и соберите его с определенным символом LUAJIT_ENABLE_GC64
:
msvcbuild.bat gc64
or XCFLAGS+= -DLUAJIT_ENABLE_GC64
in Makefile
Я использовал этот код для проверки выделения памяти:
local ffi = require("ffi")
local CHUNK_SIZE = 1 * 1024 * 1024 * 1024
local fraction_of_gb = CHUNK_SIZE / (1024*1024*1024)
local allocations = {}
for index=1, 64 do
local huge_memory_chunk = ffi.new("char[?]", CHUNK_SIZE)
table.insert(allocations, huge_memory_chunk)
print( string.format("allocated %q GB", index*fraction_of_gb) )
local pause = io.read(1)
end
print("Test complete")
local pause = io.read(1)
Выделено 48 ГБ до ошибки not enough memory
на моей машине.