Почему память LuaJIT ограничена 1-2 ГБ на 64-битных платформах?

На 64-битных платформах LuaJIT разрешает только до 1-2 ГБ данных (не считая объектов, выделенных с помощью malloc). Откуда это ограничение и почему оно даже меньше, чем на 32-битных платформах?


person bobcat    schedule 02.02.2016    source источник
comment
Можете ли вы привести ссылку на ограничение в 1 ГБ? Из всего, что я видел, ограничение составляет 2 ГБ, и те случаи, когда другие говорили, что это 1 ГБ для 64-разрядной версии, либо отклонялись, либо потоки на этом останавливались.   -  person Taegost    schedule 02.02.2016
comment
@Taegost Это 1 ГБ в Linux. я уточню   -  person bobcat    schedule 02.02.2016


Ответы (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 ГБ.

Проверьте эти ссылки для получения дополнительной информации:

person Adam    schedule 02.02.2016

Из-за недавнего патча 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 на моей машине.

введите описание изображения здесь

person Alex    schedule 23.05.2019