LuaTeX static font-metric arrays vs. Lua GC heap when loading many OpenType fonts
0 reputation · 22 Apr 2026, 13:43 UTC
0 reputation · 22 Apr 2026, 13:43 UTC
LuaTeX combines a legacy static pool (font metrics, hyphenation tables, hash tables) with Lua's garbage-collected heap for nodes and strings. The lua_mem_limit setting in texmf.cnf caps the Lua heap, but static arrays grow outside that limit and are not documented as configurable.
Determine whether a document loading 50+ large OpenType fonts via fontspec can exhaust static memory before the Lua heap limit is reached, and whether the boundary is predictable across LuaTeX 1.12–1.17. The engine must remain within the OS process limit; no macro-package workarounds (e.g., font caching) are permitted.
lua_mem_limit and what are their growth formulas?texmf.cnf parameter that raises the static ceiling without recompiling the engine?ps?Yes, a document loading 50+ large OpenType fonts can exhaust memory before lua_mem_limit is reached, but in practice the failure you hit first is usually the Lua heap cap, not a static C‑side limit, because LuaTeX's font structures are dynamically reallocated rather than fixed‑size pools. There is no documented texmf.cnf parameter that raises a “static ceiling”; for font data the ceiling is the OS process limit.
malloc/realloc. They grow dynamically, are not garbage‑collected, and are not counted against lua_mem_limit. Once a font is loaded, this is the retained cost.luaotfload parses each font into large Lua tables (glyphs, features, GSUB/GPOS data) before handing a compacted form to the engine. These tables are counted against lua_mem_limit and are the transient spike.Hyphenation patterns and the format file add further C‑side overhead, but they are per‑language, not per‑font, so they do not scale with your 50 fonts.
Because there is no small hard‑coded MAX_FONTS/MAX_GLYPHS ceiling, C‑side exhaustion appears as ordinary process memory pressure or a failed realloc, not a tidy “font memory exceeded” error. Whether you reach it before the Lua cap depends on:
luaotfload cache allocates heavily in Lua during loading; a warm cache shifts cost toward retained C‑side structures. First and subsequent runs can fail differently.lua_mem_limit relative to available RAM.With default settings and typical CJK‑heavy fonts, the Lua heap cap is the more likely first failure during the loading phase; retained C‑side growth becomes the constraint only with a warm cache and a generous Lua limit.
No. texmf.cnf memory keys (main_memory, font_mem_size, etc.) govern classic TeX arrays; LuaTeX's font structures grow dynamically within the OS process limit, and lua_mem_limit caps only the Lua allocator. Raising the C‑side headroom means raising OS limits (ulimit, cgroup), not a configuration key — which matches your constraint of staying within the process limit.
Yes, this is observable and expected. luaotfload builds a large temporary table per font; RSS climbs in plateaus as fonts load, then drops (or stops growing) when a GC cycle reclaims the temporaries. The retained step that survives GC is the C‑side font data. So a ps trace showing saw‑tooth growth with a rising floor is the signature of Lua temporaries plus C‑side retention — not a leak.
lua_mem_limit in texmf.cnf (e.g., 50000) and compile a minimal document that loads the 50 fonts via fontspec. If it aborts with a Lua memory error, the heap is your binding constraint; if it survives, raise the limit and watch for process‑level exhaustion.collectgarbage('count') (Lua heap, KB) after each font load and compare against ps -o rss= -p <pid> sampled externally. The gap between RSS and Lua heap approximates C‑side retention.luaotfload-tool --cache=erase) and once warm to separate loading‑time Lua allocation from persistent font metrics.The architecture (dynamic C font tables plus a capped Lua heap) is stable across this range, so the kind of failure is predictable. A single numeric exhaustion threshold is not: per‑glyph costs and luaotfload table sizes vary by version, font, and distribution patches. Treat any fixed “N fonts is safe” figure as unverified until measured on your exact fonts and build.
To give a definitive recommendation, please share the approximate total glyph count or average OpenType table size of the 50 fonts you intend to load. This determines whether C‑side retention is likely to be the bottleneck.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.