[{"data":1,"prerenderedAt":3760},["ShallowReactive",2],{"page-\u002Flua\u002F13-performance":3},{"id":4,"title":5,"body":6,"description":3751,"extension":3752,"meta":3753,"navigation":81,"path":3754,"seo":3755,"stem":3758,"__hash__":3759},"content\u002Flua\u002F13-performance.md","Lua 13 — Performance, Memory & LuaJIT",{"type":7,"value":8,"toc":3747},"minimark",[9,14,44,49,3743],[10,11,13],"h1",{"id":12},"_13-performance-memory-luajit","13 — Performance, Memory & LuaJIT",[15,16,17,18,22,23,26,27,30,31,35,36,39,40,43],"p",{},"Lua is fast for a scripting language, and LuaJIT is among the fastest dynamic language runtimes in existence. Performance in Lua comes from: (1) ",[19,20,21],"strong",{},"localizing"," hot-path globals, (2) avoiding ",[19,24,25],{},"table rehashing"," in tight loops, (3) using ",[19,28,29],{},"table.concat"," instead of ",[32,33,34],"code",{},".."," in loops, (4) minimizing ",[19,37,38],{},"closure allocation"," in hot paths, and (5) ",[19,41,42],{},"profiling"," before optimizing. This chapter covers the mechanics and the LuaJIT escape hatches (FFI, trace compilation).",[45,46,48],"h2",{"id":47},"global-vs-local-access-cost","Global vs Local Access Cost",[50,51,53,540,544],"code-wrapper",{"language":52},"lua",[54,55,59],"pre",{"className":56,"code":57,"language":52,"meta":58,"style":58},"language-lua shiki shiki-themes github-light github-dark","-- Global access: _G → table lookup → field lookup (2 hash lookups per access)\n-- Local access: upvalue or stack slot (direct pointer, no lookup)\n\n-- Benchmark: 10M iterations of a function call\nlocal global_fn = function(x) return x + 1 end\nlocal local_fn = global_fn  -- store as local\n\n-- BAD: global lookup per iteration\nlocal function test_global(n)\n  local sum = 0\n  for i = 1, n do\n    sum = sum + global_fn(i)  -- _G.global_fn → 2 hash lookups\n  end\n  return sum\nend\n\n-- GOOD: local upvalue, no lookup\nlocal function test_local(n)\n  local sum = 0\n  local fn = local_fn  -- localize once\n  for i = 1, n do\n    sum = sum + fn(i)  -- upvalue access, no lookup\n  end\n  return sum\nend\n\n-- Benchmark (10M iterations):\n-- test_global: ~1500ms (global lookup per call)\n-- test_local:  ~500ms (upvalue access) — 3x faster\n\n-- Production: localize ALL standard library functions used in hot paths\nlocal sformat = string.format\nlocal tinsert = table.insert\nlocal mfloor = math.floor\nlocal mrandom = math.random\nlocal pairs = pairs  -- even pairs\u002Fipairs benefit from localizing\n\nlocal function fast_format(values)\n  local out = {}\n  for i, v in ipairs(values) do  -- ipairs is a local (from above)\n    out[i] = sformat(\"%d\", v)  -- sformat is a local\n  end\n  return out\nend\n","",[32,60,61,70,76,83,89,126,143,148,154,167,181,200,220,226,235,241,246,252,264,275,291,306,325,330,337,342,347,353,359,365,370,376,389,402,415,428,444,449,462,475,498,522,527,535],{"__ignoreMap":58},[62,63,66],"span",{"class":64,"line":65},"line",1,[62,67,69],{"class":68},"sdCPZ","-- Global access: _G → table lookup → field lookup (2 hash lookups per access)\n",[62,71,73],{"class":64,"line":72},2,[62,74,75],{"class":68},"-- Local access: upvalue or stack slot (direct pointer, no lookup)\n",[62,77,79],{"class":64,"line":78},3,[62,80,82],{"emptyLinePlaceholder":81},true,"\n",[62,84,86],{"class":64,"line":85},4,[62,87,88],{"class":68},"-- Benchmark: 10M iterations of a function call\n",[62,90,92,96,100,103,106,110,113,116,119,123],{"class":64,"line":91},5,[62,93,95],{"class":94},"svdQ7","local",[62,97,99],{"class":98},"sIsaT"," global_fn",[62,101,102],{"class":94}," =",[62,104,105],{"class":94}," function",[62,107,109],{"class":108},"ssxIu","(x) ",[62,111,112],{"class":94},"return",[62,114,115],{"class":108}," x ",[62,117,118],{"class":94},"+",[62,120,122],{"class":121},"snvgF"," 1",[62,124,125],{"class":94}," end\n",[62,127,129,131,134,137,140],{"class":64,"line":128},6,[62,130,95],{"class":94},[62,132,133],{"class":108}," local_fn ",[62,135,136],{"class":94},"=",[62,138,139],{"class":108}," global_fn  ",[62,141,142],{"class":68},"-- store as local\n",[62,144,146],{"class":64,"line":145},7,[62,147,82],{"emptyLinePlaceholder":81},[62,149,151],{"class":64,"line":150},8,[62,152,153],{"class":68},"-- BAD: global lookup per iteration\n",[62,155,157,159,161,164],{"class":64,"line":156},9,[62,158,95],{"class":94},[62,160,105],{"class":94},[62,162,163],{"class":98}," test_global",[62,165,166],{"class":108},"(n)\n",[62,168,170,173,176,178],{"class":64,"line":169},10,[62,171,172],{"class":94},"  local",[62,174,175],{"class":108}," sum ",[62,177,136],{"class":94},[62,179,180],{"class":121}," 0\n",[62,182,184,187,190,192,194,197],{"class":64,"line":183},11,[62,185,186],{"class":94},"  for",[62,188,189],{"class":108}," i ",[62,191,136],{"class":94},[62,193,122],{"class":121},[62,195,196],{"class":108},", n ",[62,198,199],{"class":94},"do\n",[62,201,203,206,208,210,212,214,217],{"class":64,"line":202},12,[62,204,205],{"class":108},"    sum ",[62,207,136],{"class":94},[62,209,175],{"class":108},[62,211,118],{"class":94},[62,213,99],{"class":121},[62,215,216],{"class":108},"(i)  ",[62,218,219],{"class":68},"-- _G.global_fn → 2 hash lookups\n",[62,221,223],{"class":64,"line":222},13,[62,224,225],{"class":94},"  end\n",[62,227,229,232],{"class":64,"line":228},14,[62,230,231],{"class":94},"  return",[62,233,234],{"class":108}," sum\n",[62,236,238],{"class":64,"line":237},15,[62,239,240],{"class":94},"end\n",[62,242,244],{"class":64,"line":243},16,[62,245,82],{"emptyLinePlaceholder":81},[62,247,249],{"class":64,"line":248},17,[62,250,251],{"class":68},"-- GOOD: local upvalue, no lookup\n",[62,253,255,257,259,262],{"class":64,"line":254},18,[62,256,95],{"class":94},[62,258,105],{"class":94},[62,260,261],{"class":98}," test_local",[62,263,166],{"class":108},[62,265,267,269,271,273],{"class":64,"line":266},19,[62,268,172],{"class":94},[62,270,175],{"class":108},[62,272,136],{"class":94},[62,274,180],{"class":121},[62,276,278,280,283,285,288],{"class":64,"line":277},20,[62,279,172],{"class":94},[62,281,282],{"class":108}," fn ",[62,284,136],{"class":94},[62,286,287],{"class":108}," local_fn  ",[62,289,290],{"class":68},"-- localize once\n",[62,292,294,296,298,300,302,304],{"class":64,"line":293},21,[62,295,186],{"class":94},[62,297,189],{"class":108},[62,299,136],{"class":94},[62,301,122],{"class":121},[62,303,196],{"class":108},[62,305,199],{"class":94},[62,307,309,311,313,315,317,320,322],{"class":64,"line":308},22,[62,310,205],{"class":108},[62,312,136],{"class":94},[62,314,175],{"class":108},[62,316,118],{"class":94},[62,318,319],{"class":121}," fn",[62,321,216],{"class":108},[62,323,324],{"class":68},"-- upvalue access, no lookup\n",[62,326,328],{"class":64,"line":327},23,[62,329,225],{"class":94},[62,331,333,335],{"class":64,"line":332},24,[62,334,231],{"class":94},[62,336,234],{"class":108},[62,338,340],{"class":64,"line":339},25,[62,341,240],{"class":94},[62,343,345],{"class":64,"line":344},26,[62,346,82],{"emptyLinePlaceholder":81},[62,348,350],{"class":64,"line":349},27,[62,351,352],{"class":68},"-- Benchmark (10M iterations):\n",[62,354,356],{"class":64,"line":355},28,[62,357,358],{"class":68},"-- test_global: ~1500ms (global lookup per call)\n",[62,360,362],{"class":64,"line":361},29,[62,363,364],{"class":68},"-- test_local:  ~500ms (upvalue access) — 3x faster\n",[62,366,368],{"class":64,"line":367},30,[62,369,82],{"emptyLinePlaceholder":81},[62,371,373],{"class":64,"line":372},31,[62,374,375],{"class":68},"-- Production: localize ALL standard library functions used in hot paths\n",[62,377,379,381,384,386],{"class":64,"line":378},32,[62,380,95],{"class":94},[62,382,383],{"class":108}," sformat ",[62,385,136],{"class":94},[62,387,388],{"class":121}," string.format\n",[62,390,392,394,397,399],{"class":64,"line":391},33,[62,393,95],{"class":94},[62,395,396],{"class":108}," tinsert ",[62,398,136],{"class":94},[62,400,401],{"class":121}," table.insert\n",[62,403,405,407,410,412],{"class":64,"line":404},34,[62,406,95],{"class":94},[62,408,409],{"class":108}," mfloor ",[62,411,136],{"class":94},[62,413,414],{"class":121}," math.floor\n",[62,416,418,420,423,425],{"class":64,"line":417},35,[62,419,95],{"class":94},[62,421,422],{"class":108}," mrandom ",[62,424,136],{"class":94},[62,426,427],{"class":121}," math.random\n",[62,429,431,433,436,438,441],{"class":64,"line":430},36,[62,432,95],{"class":94},[62,434,435],{"class":108}," pairs ",[62,437,136],{"class":94},[62,439,440],{"class":121}," pairs",[62,442,443],{"class":68},"  -- even pairs\u002Fipairs benefit from localizing\n",[62,445,447],{"class":64,"line":446},37,[62,448,82],{"emptyLinePlaceholder":81},[62,450,452,454,456,459],{"class":64,"line":451},38,[62,453,95],{"class":94},[62,455,105],{"class":94},[62,457,458],{"class":98}," fast_format",[62,460,461],{"class":108},"(values)\n",[62,463,465,467,470,472],{"class":64,"line":464},39,[62,466,172],{"class":94},[62,468,469],{"class":108}," out ",[62,471,136],{"class":94},[62,473,474],{"class":108}," {}\n",[62,476,478,480,483,486,489,492,495],{"class":64,"line":477},40,[62,479,186],{"class":94},[62,481,482],{"class":108}," i, v ",[62,484,485],{"class":94},"in",[62,487,488],{"class":121}," ipairs",[62,490,491],{"class":108},"(values) ",[62,493,494],{"class":94},"do",[62,496,497],{"class":68},"  -- ipairs is a local (from above)\n",[62,499,501,504,506,509,512,516,519],{"class":64,"line":500},41,[62,502,503],{"class":108},"    out[i] ",[62,505,136],{"class":94},[62,507,508],{"class":121}," sformat",[62,510,511],{"class":108},"(",[62,513,515],{"class":514},"sJ6F3","\"%d\"",[62,517,518],{"class":108},", v)  ",[62,520,521],{"class":68},"-- sformat is a local\n",[62,523,525],{"class":64,"line":524},42,[62,526,225],{"class":94},[62,528,530,532],{"class":64,"line":529},43,[62,531,231],{"class":94},[62,533,534],{"class":108}," out\n",[62,536,538],{"class":64,"line":537},44,[62,539,240],{"class":94},[45,541,543],{"id":542},"table-pre-allocation-rehash-avoidance","Table Pre-allocation & Rehash Avoidance",[50,545,546,822,831],{"language":52},[54,547,549],{"className":56,"code":548,"language":52,"meta":58,"style":58},"-- Tables have an array part (1..n) and hash part\n-- Insertions that exceed the current capacity trigger a REHASH (O(n) — resizes both parts)\n-- The rehash strategy: doubles the capacity when full (amortized O(1) insertion)\n-- But each rehash allocates a new array + hash, copies all entries\n\n-- BAD: incremental insertion triggers log(n) rehashes\nlocal t = {}\nfor i = 1, 1000000 do\n  t[i] = i  -- rehash at 2, 4, 8, 16, ... 524288, 1048576 (20 rehashes for 1M)\nend\n-- Each rehash: O(n) copy. Total: O(n log n) with allocation spikes.\n\n-- Lua has NO table.reserve() — but you can pre-fill to force the capacity:\nlocal function preallocate(n)\n  local t = {}\n  for i = 1, n do t[i] = 0 end  -- fill with zeros (forces allocation to n)\n  return t\nend\n\n-- For known-size arrays, this avoids incremental rehashes:\nlocal t = preallocate(1000000)\nfor i = 1, 1000000 do\n  t[i] = i  -- no rehashes (capacity already at 1M)\nend\n-- Measurable: ~30% faster for large N, fewer GC pauses\n\n-- For hash part: you can't pre-allocate directly, but filling with dummy keys works:\nlocal cache = {}\nfor _, key in ipairs(known_keys) do\n  cache[key] = false  -- pre-allocate all keys\nend\n-- Then real inserts don't trigger rehashes\n",[32,550,551,556,561,566,571,575,580,591,611,624,628,633,637,642,653,663,691,698,702,706,711,728,744,755,759,764,768,773,784,800,813,817],{"__ignoreMap":58},[62,552,553],{"class":64,"line":65},[62,554,555],{"class":68},"-- Tables have an array part (1..n) and hash part\n",[62,557,558],{"class":64,"line":72},[62,559,560],{"class":68},"-- Insertions that exceed the current capacity trigger a REHASH (O(n) — resizes both parts)\n",[62,562,563],{"class":64,"line":78},[62,564,565],{"class":68},"-- The rehash strategy: doubles the capacity when full (amortized O(1) insertion)\n",[62,567,568],{"class":64,"line":85},[62,569,570],{"class":68},"-- But each rehash allocates a new array + hash, copies all entries\n",[62,572,573],{"class":64,"line":91},[62,574,82],{"emptyLinePlaceholder":81},[62,576,577],{"class":64,"line":128},[62,578,579],{"class":68},"-- BAD: incremental insertion triggers log(n) rehashes\n",[62,581,582,584,587,589],{"class":64,"line":145},[62,583,95],{"class":94},[62,585,586],{"class":108}," t ",[62,588,136],{"class":94},[62,590,474],{"class":108},[62,592,593,596,598,600,602,605,608],{"class":64,"line":150},[62,594,595],{"class":94},"for",[62,597,189],{"class":108},[62,599,136],{"class":94},[62,601,122],{"class":121},[62,603,604],{"class":108},", ",[62,606,607],{"class":121},"1000000",[62,609,610],{"class":94}," do\n",[62,612,613,616,618,621],{"class":64,"line":156},[62,614,615],{"class":108},"  t[i] ",[62,617,136],{"class":94},[62,619,620],{"class":108}," i  ",[62,622,623],{"class":68},"-- rehash at 2, 4, 8, 16, ... 524288, 1048576 (20 rehashes for 1M)\n",[62,625,626],{"class":64,"line":169},[62,627,240],{"class":94},[62,629,630],{"class":64,"line":183},[62,631,632],{"class":68},"-- Each rehash: O(n) copy. Total: O(n log n) with allocation spikes.\n",[62,634,635],{"class":64,"line":202},[62,636,82],{"emptyLinePlaceholder":81},[62,638,639],{"class":64,"line":222},[62,640,641],{"class":68},"-- Lua has NO table.reserve() — but you can pre-fill to force the capacity:\n",[62,643,644,646,648,651],{"class":64,"line":228},[62,645,95],{"class":94},[62,647,105],{"class":94},[62,649,650],{"class":98}," preallocate",[62,652,166],{"class":108},[62,654,655,657,659,661],{"class":64,"line":237},[62,656,172],{"class":94},[62,658,586],{"class":108},[62,660,136],{"class":94},[62,662,474],{"class":108},[62,664,665,667,669,671,673,675,677,680,682,685,688],{"class":64,"line":243},[62,666,186],{"class":94},[62,668,189],{"class":108},[62,670,136],{"class":94},[62,672,122],{"class":121},[62,674,196],{"class":108},[62,676,494],{"class":94},[62,678,679],{"class":108}," t[i] ",[62,681,136],{"class":94},[62,683,684],{"class":121}," 0",[62,686,687],{"class":94}," end",[62,689,690],{"class":68},"  -- fill with zeros (forces allocation to n)\n",[62,692,693,695],{"class":64,"line":248},[62,694,231],{"class":94},[62,696,697],{"class":108}," t\n",[62,699,700],{"class":64,"line":254},[62,701,240],{"class":94},[62,703,704],{"class":64,"line":266},[62,705,82],{"emptyLinePlaceholder":81},[62,707,708],{"class":64,"line":277},[62,709,710],{"class":68},"-- For known-size arrays, this avoids incremental rehashes:\n",[62,712,713,715,717,719,721,723,725],{"class":64,"line":293},[62,714,95],{"class":94},[62,716,586],{"class":108},[62,718,136],{"class":94},[62,720,650],{"class":121},[62,722,511],{"class":108},[62,724,607],{"class":121},[62,726,727],{"class":108},")\n",[62,729,730,732,734,736,738,740,742],{"class":64,"line":308},[62,731,595],{"class":94},[62,733,189],{"class":108},[62,735,136],{"class":94},[62,737,122],{"class":121},[62,739,604],{"class":108},[62,741,607],{"class":121},[62,743,610],{"class":94},[62,745,746,748,750,752],{"class":64,"line":327},[62,747,615],{"class":108},[62,749,136],{"class":94},[62,751,620],{"class":108},[62,753,754],{"class":68},"-- no rehashes (capacity already at 1M)\n",[62,756,757],{"class":64,"line":332},[62,758,240],{"class":94},[62,760,761],{"class":64,"line":339},[62,762,763],{"class":68},"-- Measurable: ~30% faster for large N, fewer GC pauses\n",[62,765,766],{"class":64,"line":344},[62,767,82],{"emptyLinePlaceholder":81},[62,769,770],{"class":64,"line":349},[62,771,772],{"class":68},"-- For hash part: you can't pre-allocate directly, but filling with dummy keys works:\n",[62,774,775,777,780,782],{"class":64,"line":355},[62,776,95],{"class":94},[62,778,779],{"class":108}," cache ",[62,781,136],{"class":94},[62,783,474],{"class":108},[62,785,786,788,791,793,795,798],{"class":64,"line":361},[62,787,595],{"class":94},[62,789,790],{"class":108}," _, key ",[62,792,485],{"class":94},[62,794,488],{"class":121},[62,796,797],{"class":108},"(known_keys) ",[62,799,199],{"class":94},[62,801,802,805,807,810],{"class":64,"line":367},[62,803,804],{"class":108},"  cache[key] ",[62,806,136],{"class":94},[62,808,809],{"class":121}," false",[62,811,812],{"class":68},"  -- pre-allocate all keys\n",[62,814,815],{"class":64,"line":372},[62,816,240],{"class":94},[62,818,819],{"class":64,"line":378},[62,820,821],{"class":68},"-- Then real inserts don't trigger rehashes\n",[45,823,825,826,828,829],{"id":824},"string-concatenation-tableconcat-vs","String Concatenation: ",[32,827,29],{}," vs ",[32,830,34],{},[50,832,833,1112,1116],{"language":52},[54,834,836],{"className":56,"code":835,"language":52,"meta":58,"style":58},"-- Strings are immutable. `a .. b` allocates a NEW string of length #a + #b.\n-- Concatenation in a loop: O(n²) — each step copies the entire accumulated string.\n\n-- BAD: quadratic allocation\nlocal function build_bad(items)\n  local result = \"\"\n  for _, item in ipairs(items) do\n    result = result .. item .. \",\"  -- allocates new string each iteration\n  end\n  return result\nend\n-- 10000 items: ~50ms, 100000 items: ~5s, 1000000: ~8 minutes (quadratic)\n\n-- GOOD: linear with table.concat\nlocal function build_good(items)\n  local parts = {}\n  for i, item in ipairs(items) do\n    parts[i] = item  -- no concat, just table assignment\n  end\n  return table.concat(parts, \",\")  -- single allocation, single copy\nend\n-- 1000000 items: ~5ms (1000x faster than .. for large N)\n\n-- EVEN BETTER: pre-allocate the parts table if size is known\nlocal function build_best(items)\n  local parts = {}\n  for i = 1, #items do  -- pre-fill to allocate\n    parts[i] = items[i]\n  end\n  return table.concat(parts, \",\")\nend\n",[32,837,838,843,848,852,857,869,881,897,919,923,930,934,939,943,948,959,970,985,998,1002,1021,1025,1030,1034,1039,1050,1060,1083,1092,1096,1108],{"__ignoreMap":58},[62,839,840],{"class":64,"line":65},[62,841,842],{"class":68},"-- Strings are immutable. `a .. b` allocates a NEW string of length #a + #b.\n",[62,844,845],{"class":64,"line":72},[62,846,847],{"class":68},"-- Concatenation in a loop: O(n²) — each step copies the entire accumulated string.\n",[62,849,850],{"class":64,"line":78},[62,851,82],{"emptyLinePlaceholder":81},[62,853,854],{"class":64,"line":85},[62,855,856],{"class":68},"-- BAD: quadratic allocation\n",[62,858,859,861,863,866],{"class":64,"line":91},[62,860,95],{"class":94},[62,862,105],{"class":94},[62,864,865],{"class":98}," build_bad",[62,867,868],{"class":108},"(items)\n",[62,870,871,873,876,878],{"class":64,"line":128},[62,872,172],{"class":94},[62,874,875],{"class":108}," result ",[62,877,136],{"class":94},[62,879,880],{"class":514}," \"\"\n",[62,882,883,885,888,890,892,895],{"class":64,"line":145},[62,884,186],{"class":94},[62,886,887],{"class":108}," _, item ",[62,889,485],{"class":94},[62,891,488],{"class":121},[62,893,894],{"class":108},"(items) ",[62,896,199],{"class":94},[62,898,899,902,904,906,908,911,913,916],{"class":64,"line":150},[62,900,901],{"class":108},"    result ",[62,903,136],{"class":94},[62,905,875],{"class":108},[62,907,34],{"class":94},[62,909,910],{"class":108}," item ",[62,912,34],{"class":94},[62,914,915],{"class":514}," \",\"  ",[62,917,918],{"class":68},"-- allocates new string each iteration\n",[62,920,921],{"class":64,"line":156},[62,922,225],{"class":94},[62,924,925,927],{"class":64,"line":169},[62,926,231],{"class":94},[62,928,929],{"class":108}," result\n",[62,931,932],{"class":64,"line":183},[62,933,240],{"class":94},[62,935,936],{"class":64,"line":202},[62,937,938],{"class":68},"-- 10000 items: ~50ms, 100000 items: ~5s, 1000000: ~8 minutes (quadratic)\n",[62,940,941],{"class":64,"line":222},[62,942,82],{"emptyLinePlaceholder":81},[62,944,945],{"class":64,"line":228},[62,946,947],{"class":68},"-- GOOD: linear with table.concat\n",[62,949,950,952,954,957],{"class":64,"line":237},[62,951,95],{"class":94},[62,953,105],{"class":94},[62,955,956],{"class":98}," build_good",[62,958,868],{"class":108},[62,960,961,963,966,968],{"class":64,"line":243},[62,962,172],{"class":94},[62,964,965],{"class":108}," parts ",[62,967,136],{"class":94},[62,969,474],{"class":108},[62,971,972,974,977,979,981,983],{"class":64,"line":248},[62,973,186],{"class":94},[62,975,976],{"class":108}," i, item ",[62,978,485],{"class":94},[62,980,488],{"class":121},[62,982,894],{"class":108},[62,984,199],{"class":94},[62,986,987,990,992,995],{"class":64,"line":254},[62,988,989],{"class":108},"    parts[i] ",[62,991,136],{"class":94},[62,993,994],{"class":108}," item  ",[62,996,997],{"class":68},"-- no concat, just table assignment\n",[62,999,1000],{"class":64,"line":266},[62,1001,225],{"class":94},[62,1003,1004,1006,1009,1012,1015,1018],{"class":64,"line":277},[62,1005,231],{"class":94},[62,1007,1008],{"class":121}," table.concat",[62,1010,1011],{"class":108},"(parts, ",[62,1013,1014],{"class":514},"\",\"",[62,1016,1017],{"class":108},")  ",[62,1019,1020],{"class":68},"-- single allocation, single copy\n",[62,1022,1023],{"class":64,"line":293},[62,1024,240],{"class":94},[62,1026,1027],{"class":64,"line":308},[62,1028,1029],{"class":68},"-- 1000000 items: ~5ms (1000x faster than .. for large N)\n",[62,1031,1032],{"class":64,"line":327},[62,1033,82],{"emptyLinePlaceholder":81},[62,1035,1036],{"class":64,"line":332},[62,1037,1038],{"class":68},"-- EVEN BETTER: pre-allocate the parts table if size is known\n",[62,1040,1041,1043,1045,1048],{"class":64,"line":339},[62,1042,95],{"class":94},[62,1044,105],{"class":94},[62,1046,1047],{"class":98}," build_best",[62,1049,868],{"class":108},[62,1051,1052,1054,1056,1058],{"class":64,"line":344},[62,1053,172],{"class":94},[62,1055,965],{"class":108},[62,1057,136],{"class":94},[62,1059,474],{"class":108},[62,1061,1062,1064,1066,1068,1070,1072,1075,1078,1080],{"class":64,"line":349},[62,1063,186],{"class":94},[62,1065,189],{"class":108},[62,1067,136],{"class":94},[62,1069,122],{"class":121},[62,1071,604],{"class":108},[62,1073,1074],{"class":94},"#",[62,1076,1077],{"class":108},"items ",[62,1079,494],{"class":94},[62,1081,1082],{"class":68},"  -- pre-fill to allocate\n",[62,1084,1085,1087,1089],{"class":64,"line":355},[62,1086,989],{"class":108},[62,1088,136],{"class":94},[62,1090,1091],{"class":108}," items[i]\n",[62,1093,1094],{"class":64,"line":361},[62,1095,225],{"class":94},[62,1097,1098,1100,1102,1104,1106],{"class":64,"line":367},[62,1099,231],{"class":94},[62,1101,1008],{"class":121},[62,1103,1011],{"class":108},[62,1105,1014],{"class":514},[62,1107,727],{"class":108},[62,1109,1110],{"class":64,"line":372},[62,1111,240],{"class":94},[45,1113,1115],{"id":1114},"closure-allocation-in-hot-loops","Closure Allocation in Hot Loops",[50,1117,1118,1419,1426],{"language":52},[54,1119,1121],{"className":56,"code":1120,"language":52,"meta":58,"style":58},"-- Each `function() ... end` expression allocates a new closure object\n-- In a hot loop, this creates GC pressure\n\n-- BAD: allocates a closure per iteration\nlocal function process_bad(items, transform)\n  local results = {}\n  for i, item in ipairs(items) do\n    results[i] = (function(x) return x * 2 end)(item)  -- closure allocated per iteration\n  end\n  return results\nend\n\n-- GOOD: hoist the closure out of the loop\nlocal function process_good(items)\n  local results = {}\n  local double = function(x) return x * 2 end  -- allocate ONCE\n  for i, item in ipairs(items) do\n    results[i] = double(item)\n  end\n  return results\nend\n\n-- BEST: no closure at all (direct logic)\nlocal function process_best(items)\n  local results = {}\n  for i, item in ipairs(items) do\n    results[i] = item * 2  -- no function call, no closure\n  end\n  return results\nend\n\n-- Benchmark (1M items):\n-- process_bad:  ~300ms (closure allocation + GC pressure)\n-- process_good: ~100ms (closure allocated once)\n-- process_best: ~50ms  (no closure, no call overhead)\n",[32,1122,1123,1128,1133,1137,1142,1154,1165,1179,1212,1216,1223,1227,1231,1236,1247,1257,1283,1297,1308,1312,1318,1322,1326,1331,1342,1352,1366,1381,1385,1391,1395,1399,1404,1409,1414],{"__ignoreMap":58},[62,1124,1125],{"class":64,"line":65},[62,1126,1127],{"class":68},"-- Each `function() ... end` expression allocates a new closure object\n",[62,1129,1130],{"class":64,"line":72},[62,1131,1132],{"class":68},"-- In a hot loop, this creates GC pressure\n",[62,1134,1135],{"class":64,"line":78},[62,1136,82],{"emptyLinePlaceholder":81},[62,1138,1139],{"class":64,"line":85},[62,1140,1141],{"class":68},"-- BAD: allocates a closure per iteration\n",[62,1143,1144,1146,1148,1151],{"class":64,"line":91},[62,1145,95],{"class":94},[62,1147,105],{"class":94},[62,1149,1150],{"class":98}," process_bad",[62,1152,1153],{"class":108},"(items, transform)\n",[62,1155,1156,1158,1161,1163],{"class":64,"line":128},[62,1157,172],{"class":94},[62,1159,1160],{"class":108}," results ",[62,1162,136],{"class":94},[62,1164,474],{"class":108},[62,1166,1167,1169,1171,1173,1175,1177],{"class":64,"line":145},[62,1168,186],{"class":94},[62,1170,976],{"class":108},[62,1172,485],{"class":94},[62,1174,488],{"class":121},[62,1176,894],{"class":108},[62,1178,199],{"class":94},[62,1180,1181,1184,1186,1189,1192,1194,1196,1198,1201,1204,1206,1209],{"class":64,"line":150},[62,1182,1183],{"class":108},"    results[i] ",[62,1185,136],{"class":94},[62,1187,1188],{"class":108}," (",[62,1190,1191],{"class":94},"function",[62,1193,109],{"class":108},[62,1195,112],{"class":94},[62,1197,115],{"class":108},[62,1199,1200],{"class":94},"*",[62,1202,1203],{"class":121}," 2",[62,1205,687],{"class":94},[62,1207,1208],{"class":108},")(item)  ",[62,1210,1211],{"class":68},"-- closure allocated per iteration\n",[62,1213,1214],{"class":64,"line":156},[62,1215,225],{"class":94},[62,1217,1218,1220],{"class":64,"line":169},[62,1219,231],{"class":94},[62,1221,1222],{"class":108}," results\n",[62,1224,1225],{"class":64,"line":183},[62,1226,240],{"class":94},[62,1228,1229],{"class":64,"line":202},[62,1230,82],{"emptyLinePlaceholder":81},[62,1232,1233],{"class":64,"line":222},[62,1234,1235],{"class":68},"-- GOOD: hoist the closure out of the loop\n",[62,1237,1238,1240,1242,1245],{"class":64,"line":228},[62,1239,95],{"class":94},[62,1241,105],{"class":94},[62,1243,1244],{"class":98}," process_good",[62,1246,868],{"class":108},[62,1248,1249,1251,1253,1255],{"class":64,"line":237},[62,1250,172],{"class":94},[62,1252,1160],{"class":108},[62,1254,136],{"class":94},[62,1256,474],{"class":108},[62,1258,1259,1261,1264,1266,1268,1270,1272,1274,1276,1278,1280],{"class":64,"line":243},[62,1260,172],{"class":94},[62,1262,1263],{"class":98}," double",[62,1265,102],{"class":94},[62,1267,105],{"class":94},[62,1269,109],{"class":108},[62,1271,112],{"class":94},[62,1273,115],{"class":108},[62,1275,1200],{"class":94},[62,1277,1203],{"class":121},[62,1279,687],{"class":94},[62,1281,1282],{"class":68},"  -- allocate ONCE\n",[62,1284,1285,1287,1289,1291,1293,1295],{"class":64,"line":248},[62,1286,186],{"class":94},[62,1288,976],{"class":108},[62,1290,485],{"class":94},[62,1292,488],{"class":121},[62,1294,894],{"class":108},[62,1296,199],{"class":94},[62,1298,1299,1301,1303,1305],{"class":64,"line":254},[62,1300,1183],{"class":108},[62,1302,136],{"class":94},[62,1304,1263],{"class":121},[62,1306,1307],{"class":108},"(item)\n",[62,1309,1310],{"class":64,"line":266},[62,1311,225],{"class":94},[62,1313,1314,1316],{"class":64,"line":277},[62,1315,231],{"class":94},[62,1317,1222],{"class":108},[62,1319,1320],{"class":64,"line":293},[62,1321,240],{"class":94},[62,1323,1324],{"class":64,"line":308},[62,1325,82],{"emptyLinePlaceholder":81},[62,1327,1328],{"class":64,"line":327},[62,1329,1330],{"class":68},"-- BEST: no closure at all (direct logic)\n",[62,1332,1333,1335,1337,1340],{"class":64,"line":332},[62,1334,95],{"class":94},[62,1336,105],{"class":94},[62,1338,1339],{"class":98}," process_best",[62,1341,868],{"class":108},[62,1343,1344,1346,1348,1350],{"class":64,"line":339},[62,1345,172],{"class":94},[62,1347,1160],{"class":108},[62,1349,136],{"class":94},[62,1351,474],{"class":108},[62,1353,1354,1356,1358,1360,1362,1364],{"class":64,"line":344},[62,1355,186],{"class":94},[62,1357,976],{"class":108},[62,1359,485],{"class":94},[62,1361,488],{"class":121},[62,1363,894],{"class":108},[62,1365,199],{"class":94},[62,1367,1368,1370,1372,1374,1376,1378],{"class":64,"line":349},[62,1369,1183],{"class":108},[62,1371,136],{"class":94},[62,1373,910],{"class":108},[62,1375,1200],{"class":94},[62,1377,1203],{"class":121},[62,1379,1380],{"class":68},"  -- no function call, no closure\n",[62,1382,1383],{"class":64,"line":355},[62,1384,225],{"class":94},[62,1386,1387,1389],{"class":64,"line":361},[62,1388,231],{"class":94},[62,1390,1222],{"class":108},[62,1392,1393],{"class":64,"line":367},[62,1394,240],{"class":94},[62,1396,1397],{"class":64,"line":372},[62,1398,82],{"emptyLinePlaceholder":81},[62,1400,1401],{"class":64,"line":378},[62,1402,1403],{"class":68},"-- Benchmark (1M items):\n",[62,1405,1406],{"class":64,"line":391},[62,1407,1408],{"class":68},"-- process_bad:  ~300ms (closure allocation + GC pressure)\n",[62,1410,1411],{"class":64,"line":404},[62,1412,1413],{"class":68},"-- process_good: ~100ms (closure allocated once)\n",[62,1415,1416],{"class":64,"line":417},[62,1417,1418],{"class":68},"-- process_best: ~50ms  (no closure, no call overhead)\n",[45,1420,1422,1423],{"id":1421},"memory-profiling-with-collectgarbage","Memory Profiling with ",[32,1424,1425],{},"collectgarbage",[50,1427,1428,1774,1778],{"language":52},[54,1429,1431],{"className":56,"code":1430,"language":52,"meta":58,"style":58},"-- collectgarbage(option, arg): control the garbage collector\ncollectgarbage(\"collect\")  -- full GC cycle (force collection)\ncollectgarbage(\"count\")    -- current memory usage in KB (returns number)\ncollectgarbage(\"stop\")     -- disable GC (for benchmarking — no GC pauses)\ncollectgarbage(\"restart\")  -- re-enable GC\ncollectgarbage(\"step\")     -- perform one GC step\ncollectgarbage(\"setpause\", 200)   -- GC pause: run when memory grows by 200% (default 200)\ncollectgarbage(\"setstepmul\", 200) -- GC step multiplier (default 200)\n\n-- Memory measurement pattern:\nlocal function measure_memory(fn)\n  collectgarbage(\"collect\")  -- full GC before measuring\n  local before = collectgarbage(\"count\")  -- KB\n  fn()\n  collectgarbage(\"collect\")  -- force GC of temporaries\n  local after = collectgarbage(\"count\")\n  return (after - before), after  -- delta KB, total KB\nend\n\nlocal delta, total = measure_memory(function()\n  local t = {}\n  for i = 1, 100000 do t[i] = i end\nend)\nprint(string.format(\"allocated: %.1f KB, current: %.1f KB\", delta, total))\n-- Note: if `t` goes out of scope and is collected, delta may be 0 (all freed)\n-- To measure peak: don't collect between fn and measurement\n\n-- GC tuning for throughput vs latency:\n-- For batch processing: collectgarbage(\"setpause\", 500)  — less frequent GC\n-- For interactive\u002Freal-time: collectgarbage(\"setpause\", 100)  — more frequent, smaller pauses\n",[32,1432,1433,1438,1452,1467,1482,1496,1510,1530,1549,1553,1558,1570,1584,1605,1613,1626,1643,1659,1663,1667,1684,1694,1720,1727,1745,1750,1755,1759,1764,1769],{"__ignoreMap":58},[62,1434,1435],{"class":64,"line":65},[62,1436,1437],{"class":68},"-- collectgarbage(option, arg): control the garbage collector\n",[62,1439,1440,1442,1444,1447,1449],{"class":64,"line":72},[62,1441,1425],{"class":121},[62,1443,511],{"class":108},[62,1445,1446],{"class":514},"\"collect\"",[62,1448,1017],{"class":108},[62,1450,1451],{"class":68},"-- full GC cycle (force collection)\n",[62,1453,1454,1456,1458,1461,1464],{"class":64,"line":78},[62,1455,1425],{"class":121},[62,1457,511],{"class":108},[62,1459,1460],{"class":514},"\"count\"",[62,1462,1463],{"class":108},")    ",[62,1465,1466],{"class":68},"-- current memory usage in KB (returns number)\n",[62,1468,1469,1471,1473,1476,1479],{"class":64,"line":85},[62,1470,1425],{"class":121},[62,1472,511],{"class":108},[62,1474,1475],{"class":514},"\"stop\"",[62,1477,1478],{"class":108},")     ",[62,1480,1481],{"class":68},"-- disable GC (for benchmarking — no GC pauses)\n",[62,1483,1484,1486,1488,1491,1493],{"class":64,"line":91},[62,1485,1425],{"class":121},[62,1487,511],{"class":108},[62,1489,1490],{"class":514},"\"restart\"",[62,1492,1017],{"class":108},[62,1494,1495],{"class":68},"-- re-enable GC\n",[62,1497,1498,1500,1502,1505,1507],{"class":64,"line":128},[62,1499,1425],{"class":121},[62,1501,511],{"class":108},[62,1503,1504],{"class":514},"\"step\"",[62,1506,1478],{"class":108},[62,1508,1509],{"class":68},"-- perform one GC step\n",[62,1511,1512,1514,1516,1519,1521,1524,1527],{"class":64,"line":145},[62,1513,1425],{"class":121},[62,1515,511],{"class":108},[62,1517,1518],{"class":514},"\"setpause\"",[62,1520,604],{"class":108},[62,1522,1523],{"class":121},"200",[62,1525,1526],{"class":108},")   ",[62,1528,1529],{"class":68},"-- GC pause: run when memory grows by 200% (default 200)\n",[62,1531,1532,1534,1536,1539,1541,1543,1546],{"class":64,"line":150},[62,1533,1425],{"class":121},[62,1535,511],{"class":108},[62,1537,1538],{"class":514},"\"setstepmul\"",[62,1540,604],{"class":108},[62,1542,1523],{"class":121},[62,1544,1545],{"class":108},") ",[62,1547,1548],{"class":68},"-- GC step multiplier (default 200)\n",[62,1550,1551],{"class":64,"line":156},[62,1552,82],{"emptyLinePlaceholder":81},[62,1554,1555],{"class":64,"line":169},[62,1556,1557],{"class":68},"-- Memory measurement pattern:\n",[62,1559,1560,1562,1564,1567],{"class":64,"line":183},[62,1561,95],{"class":94},[62,1563,105],{"class":94},[62,1565,1566],{"class":98}," measure_memory",[62,1568,1569],{"class":108},"(fn)\n",[62,1571,1572,1575,1577,1579,1581],{"class":64,"line":202},[62,1573,1574],{"class":121},"  collectgarbage",[62,1576,511],{"class":108},[62,1578,1446],{"class":514},[62,1580,1017],{"class":108},[62,1582,1583],{"class":68},"-- full GC before measuring\n",[62,1585,1586,1588,1591,1593,1596,1598,1600,1602],{"class":64,"line":222},[62,1587,172],{"class":94},[62,1589,1590],{"class":108}," before ",[62,1592,136],{"class":94},[62,1594,1595],{"class":121}," collectgarbage",[62,1597,511],{"class":108},[62,1599,1460],{"class":514},[62,1601,1017],{"class":108},[62,1603,1604],{"class":68},"-- KB\n",[62,1606,1607,1610],{"class":64,"line":228},[62,1608,1609],{"class":121},"  fn",[62,1611,1612],{"class":108},"()\n",[62,1614,1615,1617,1619,1621,1623],{"class":64,"line":237},[62,1616,1574],{"class":121},[62,1618,511],{"class":108},[62,1620,1446],{"class":514},[62,1622,1017],{"class":108},[62,1624,1625],{"class":68},"-- force GC of temporaries\n",[62,1627,1628,1630,1633,1635,1637,1639,1641],{"class":64,"line":243},[62,1629,172],{"class":94},[62,1631,1632],{"class":108}," after ",[62,1634,136],{"class":94},[62,1636,1595],{"class":121},[62,1638,511],{"class":108},[62,1640,1460],{"class":514},[62,1642,727],{"class":108},[62,1644,1645,1647,1650,1653,1656],{"class":64,"line":248},[62,1646,231],{"class":94},[62,1648,1649],{"class":108}," (after ",[62,1651,1652],{"class":94},"-",[62,1654,1655],{"class":108}," before), after  ",[62,1657,1658],{"class":68},"-- delta KB, total KB\n",[62,1660,1661],{"class":64,"line":254},[62,1662,240],{"class":94},[62,1664,1665],{"class":64,"line":266},[62,1666,82],{"emptyLinePlaceholder":81},[62,1668,1669,1671,1674,1676,1678,1680,1682],{"class":64,"line":277},[62,1670,95],{"class":94},[62,1672,1673],{"class":108}," delta, total ",[62,1675,136],{"class":94},[62,1677,1566],{"class":121},[62,1679,511],{"class":108},[62,1681,1191],{"class":94},[62,1683,1612],{"class":108},[62,1685,1686,1688,1690,1692],{"class":64,"line":293},[62,1687,172],{"class":94},[62,1689,586],{"class":108},[62,1691,136],{"class":94},[62,1693,474],{"class":108},[62,1695,1696,1698,1700,1702,1704,1706,1709,1712,1714,1716,1718],{"class":64,"line":308},[62,1697,186],{"class":94},[62,1699,189],{"class":108},[62,1701,136],{"class":94},[62,1703,122],{"class":121},[62,1705,604],{"class":108},[62,1707,1708],{"class":121},"100000",[62,1710,1711],{"class":94}," do",[62,1713,679],{"class":108},[62,1715,136],{"class":94},[62,1717,189],{"class":108},[62,1719,240],{"class":94},[62,1721,1722,1725],{"class":64,"line":327},[62,1723,1724],{"class":94},"end",[62,1726,727],{"class":108},[62,1728,1729,1732,1734,1737,1739,1742],{"class":64,"line":332},[62,1730,1731],{"class":121},"print",[62,1733,511],{"class":108},[62,1735,1736],{"class":121},"string.format",[62,1738,511],{"class":108},[62,1740,1741],{"class":514},"\"allocated: %.1f KB, current: %.1f KB\"",[62,1743,1744],{"class":108},", delta, total))\n",[62,1746,1747],{"class":64,"line":339},[62,1748,1749],{"class":68},"-- Note: if `t` goes out of scope and is collected, delta may be 0 (all freed)\n",[62,1751,1752],{"class":64,"line":344},[62,1753,1754],{"class":68},"-- To measure peak: don't collect between fn and measurement\n",[62,1756,1757],{"class":64,"line":349},[62,1758,82],{"emptyLinePlaceholder":81},[62,1760,1761],{"class":64,"line":355},[62,1762,1763],{"class":68},"-- GC tuning for throughput vs latency:\n",[62,1765,1766],{"class":64,"line":361},[62,1767,1768],{"class":68},"-- For batch processing: collectgarbage(\"setpause\", 500)  — less frequent GC\n",[62,1770,1771],{"class":64,"line":367},[62,1772,1773],{"class":68},"-- For interactive\u002Freal-time: collectgarbage(\"setpause\", 100)  — more frequent, smaller pauses\n",[45,1775,1777],{"id":1776},"benchmarking-methodology","Benchmarking Methodology",[50,1779,1780,2194,2206],{"language":52},[54,1781,1783],{"className":56,"code":1782,"language":52,"meta":58,"style":58},"-- Correct benchmarking: disable GC, warm up, multiple runs, measure CPU time\nlocal function benchmark(name, fn, iterations)\n  iterations = iterations or 1000000\n  -- Warm up: let the JIT (if LuaJIT) compile, populate caches\n  for i = 1, 1000 do fn() end\n  -- Disable GC during measurement (avoids GC pause noise)\n  collectgarbage(\"stop\")\n  local start = os.clock()\n  for i = 1, iterations do\n    fn()\n  end\n  local elapsed = os.clock() - start\n  collectgarbage(\"restart\")\n  local ns_per_op = elapsed \u002F iterations * 1e9\n  print(string.format(\"%s: %.2f ns\u002Fop (%d ops in %.3fs)\",\n    name, ns_per_op, iterations, elapsed))\n  return elapsed\nend\n\n-- Compare implementations:\nbenchmark(\"table.insert\", function()\n  local t = {}\n  for i = 1, 100 do table.insert(t, i) end\nend)\n\nbenchmark(\"t[#t+1]=\", function()\n  local t = {}\n  for i = 1, 100 do t[#t + 1] = i end\nend)\n\nbenchmark(\"t[i]= (pre-size)\", function()\n  local t = {}\n  for i = 1, 100 do t[i] = i end  -- no # call, direct index\nend)\n-- Result: t[i]= is fastest (no function call, no # evaluation), t[#t+1]= second,\n-- table.insert slowest (function call overhead + length check)\n",[32,1784,1785,1790,1802,1818,1823,1847,1852,1862,1876,1891,1898,1902,1920,1930,1951,1968,1973,1980,1984,1988,1993,2009,2019,2044,2050,2054,2069,2079,2116,2122,2126,2141,2151,2178,2184,2189],{"__ignoreMap":58},[62,1786,1787],{"class":64,"line":65},[62,1788,1789],{"class":68},"-- Correct benchmarking: disable GC, warm up, multiple runs, measure CPU time\n",[62,1791,1792,1794,1796,1799],{"class":64,"line":72},[62,1793,95],{"class":94},[62,1795,105],{"class":94},[62,1797,1798],{"class":98}," benchmark",[62,1800,1801],{"class":108},"(name, fn, iterations)\n",[62,1803,1804,1807,1809,1812,1815],{"class":64,"line":78},[62,1805,1806],{"class":108},"  iterations ",[62,1808,136],{"class":94},[62,1810,1811],{"class":108}," iterations ",[62,1813,1814],{"class":94},"or",[62,1816,1817],{"class":121}," 1000000\n",[62,1819,1820],{"class":64,"line":85},[62,1821,1822],{"class":68},"  -- Warm up: let the JIT (if LuaJIT) compile, populate caches\n",[62,1824,1825,1827,1829,1831,1833,1835,1838,1840,1842,1845],{"class":64,"line":91},[62,1826,186],{"class":94},[62,1828,189],{"class":108},[62,1830,136],{"class":94},[62,1832,122],{"class":121},[62,1834,604],{"class":108},[62,1836,1837],{"class":121},"1000",[62,1839,1711],{"class":94},[62,1841,319],{"class":121},[62,1843,1844],{"class":108},"() ",[62,1846,240],{"class":94},[62,1848,1849],{"class":64,"line":128},[62,1850,1851],{"class":68},"  -- Disable GC during measurement (avoids GC pause noise)\n",[62,1853,1854,1856,1858,1860],{"class":64,"line":145},[62,1855,1574],{"class":121},[62,1857,511],{"class":108},[62,1859,1475],{"class":514},[62,1861,727],{"class":108},[62,1863,1864,1866,1869,1871,1874],{"class":64,"line":150},[62,1865,172],{"class":94},[62,1867,1868],{"class":108}," start ",[62,1870,136],{"class":94},[62,1872,1873],{"class":121}," os.clock",[62,1875,1612],{"class":108},[62,1877,1878,1880,1882,1884,1886,1889],{"class":64,"line":156},[62,1879,186],{"class":94},[62,1881,189],{"class":108},[62,1883,136],{"class":94},[62,1885,122],{"class":121},[62,1887,1888],{"class":108},", iterations ",[62,1890,199],{"class":94},[62,1892,1893,1896],{"class":64,"line":169},[62,1894,1895],{"class":121},"    fn",[62,1897,1612],{"class":108},[62,1899,1900],{"class":64,"line":183},[62,1901,225],{"class":94},[62,1903,1904,1906,1909,1911,1913,1915,1917],{"class":64,"line":202},[62,1905,172],{"class":94},[62,1907,1908],{"class":108}," elapsed ",[62,1910,136],{"class":94},[62,1912,1873],{"class":121},[62,1914,1844],{"class":108},[62,1916,1652],{"class":94},[62,1918,1919],{"class":108}," start\n",[62,1921,1922,1924,1926,1928],{"class":64,"line":222},[62,1923,1574],{"class":121},[62,1925,511],{"class":108},[62,1927,1490],{"class":514},[62,1929,727],{"class":108},[62,1931,1932,1934,1937,1939,1941,1944,1946,1948],{"class":64,"line":228},[62,1933,172],{"class":94},[62,1935,1936],{"class":108}," ns_per_op ",[62,1938,136],{"class":94},[62,1940,1908],{"class":108},[62,1942,1943],{"class":94},"\u002F",[62,1945,1811],{"class":108},[62,1947,1200],{"class":94},[62,1949,1950],{"class":121}," 1e9\n",[62,1952,1953,1956,1958,1960,1962,1965],{"class":64,"line":237},[62,1954,1955],{"class":121},"  print",[62,1957,511],{"class":108},[62,1959,1736],{"class":121},[62,1961,511],{"class":108},[62,1963,1964],{"class":514},"\"%s: %.2f ns\u002Fop (%d ops in %.3fs)\"",[62,1966,1967],{"class":108},",\n",[62,1969,1970],{"class":64,"line":243},[62,1971,1972],{"class":108},"    name, ns_per_op, iterations, elapsed))\n",[62,1974,1975,1977],{"class":64,"line":248},[62,1976,231],{"class":94},[62,1978,1979],{"class":108}," elapsed\n",[62,1981,1982],{"class":64,"line":254},[62,1983,240],{"class":94},[62,1985,1986],{"class":64,"line":266},[62,1987,82],{"emptyLinePlaceholder":81},[62,1989,1990],{"class":64,"line":277},[62,1991,1992],{"class":68},"-- Compare implementations:\n",[62,1994,1995,1998,2000,2003,2005,2007],{"class":64,"line":293},[62,1996,1997],{"class":121},"benchmark",[62,1999,511],{"class":108},[62,2001,2002],{"class":514},"\"table.insert\"",[62,2004,604],{"class":108},[62,2006,1191],{"class":94},[62,2008,1612],{"class":108},[62,2010,2011,2013,2015,2017],{"class":64,"line":308},[62,2012,172],{"class":94},[62,2014,586],{"class":108},[62,2016,136],{"class":94},[62,2018,474],{"class":108},[62,2020,2021,2023,2025,2027,2029,2031,2034,2036,2039,2042],{"class":64,"line":327},[62,2022,186],{"class":94},[62,2024,189],{"class":108},[62,2026,136],{"class":94},[62,2028,122],{"class":121},[62,2030,604],{"class":108},[62,2032,2033],{"class":121},"100",[62,2035,1711],{"class":94},[62,2037,2038],{"class":121}," table.insert",[62,2040,2041],{"class":108},"(t, i) ",[62,2043,240],{"class":94},[62,2045,2046,2048],{"class":64,"line":332},[62,2047,1724],{"class":94},[62,2049,727],{"class":108},[62,2051,2052],{"class":64,"line":339},[62,2053,82],{"emptyLinePlaceholder":81},[62,2055,2056,2058,2060,2063,2065,2067],{"class":64,"line":344},[62,2057,1997],{"class":121},[62,2059,511],{"class":108},[62,2061,2062],{"class":514},"\"t[#t+1]=\"",[62,2064,604],{"class":108},[62,2066,1191],{"class":94},[62,2068,1612],{"class":108},[62,2070,2071,2073,2075,2077],{"class":64,"line":349},[62,2072,172],{"class":94},[62,2074,586],{"class":108},[62,2076,136],{"class":94},[62,2078,474],{"class":108},[62,2080,2081,2083,2085,2087,2089,2091,2093,2095,2098,2100,2103,2105,2107,2110,2112,2114],{"class":64,"line":355},[62,2082,186],{"class":94},[62,2084,189],{"class":108},[62,2086,136],{"class":94},[62,2088,122],{"class":121},[62,2090,604],{"class":108},[62,2092,2033],{"class":121},[62,2094,1711],{"class":94},[62,2096,2097],{"class":108}," t[",[62,2099,1074],{"class":94},[62,2101,2102],{"class":108},"t ",[62,2104,118],{"class":94},[62,2106,122],{"class":121},[62,2108,2109],{"class":108},"] ",[62,2111,136],{"class":94},[62,2113,189],{"class":108},[62,2115,240],{"class":94},[62,2117,2118,2120],{"class":64,"line":361},[62,2119,1724],{"class":94},[62,2121,727],{"class":108},[62,2123,2124],{"class":64,"line":367},[62,2125,82],{"emptyLinePlaceholder":81},[62,2127,2128,2130,2132,2135,2137,2139],{"class":64,"line":372},[62,2129,1997],{"class":121},[62,2131,511],{"class":108},[62,2133,2134],{"class":514},"\"t[i]= (pre-size)\"",[62,2136,604],{"class":108},[62,2138,1191],{"class":94},[62,2140,1612],{"class":108},[62,2142,2143,2145,2147,2149],{"class":64,"line":378},[62,2144,172],{"class":94},[62,2146,586],{"class":108},[62,2148,136],{"class":94},[62,2150,474],{"class":108},[62,2152,2153,2155,2157,2159,2161,2163,2165,2167,2169,2171,2173,2175],{"class":64,"line":391},[62,2154,186],{"class":94},[62,2156,189],{"class":108},[62,2158,136],{"class":94},[62,2160,122],{"class":121},[62,2162,604],{"class":108},[62,2164,2033],{"class":121},[62,2166,1711],{"class":94},[62,2168,679],{"class":108},[62,2170,136],{"class":94},[62,2172,189],{"class":108},[62,2174,1724],{"class":94},[62,2176,2177],{"class":68},"  -- no # call, direct index\n",[62,2179,2180,2182],{"class":64,"line":404},[62,2181,1724],{"class":94},[62,2183,727],{"class":108},[62,2185,2186],{"class":64,"line":417},[62,2187,2188],{"class":68},"-- Result: t[i]= is fastest (no function call, no # evaluation), t[#t+1]= second,\n",[62,2190,2191],{"class":64,"line":430},[62,2192,2193],{"class":68},"-- table.insert slowest (function call overhead + length check)\n",[45,2195,2197,828,2200,828,2203],{"id":2196},"ipairs-vs-pairs-vs-for-i-1-t",[32,2198,2199],{},"ipairs",[32,2201,2202],{},"pairs",[32,2204,2205],{},"for i = 1, #t",[50,2207,2208,2493,2497],{"language":52},[54,2209,2211],{"className":56,"code":2210,"language":52,"meta":58,"style":58},"-- Fastest: for i = 1, #t do (numeric loop, no function call per iteration)\nlocal function fast_iter(t)\n  local n = #t  -- evaluate length ONCE\n  local sum = 0\n  for i = 1, n do\n    sum = sum + t[i]\n  end\n  return sum\nend\n\n-- Slower: ipairs (iterator function call per iteration)\nlocal function medium_iter(t)\n  local sum = 0\n  for _, v in ipairs(t) do  -- ipairs_iter function called per element\n    sum = sum + v\n  end\n  return sum\nend\n\n-- Slowest for arrays: pairs (iterates hash part too, unordered)\nlocal function slow_iter(t)\n  local sum = 0\n  for _, v in pairs(t) do  -- next() called per element; visits ALL keys\n    if type(v) == \"number\" then sum = sum + v end\n  end\n  return sum\nend\n\n-- Benchmark (1M element array):\n-- fast_iter:   ~5ms   (numeric loop, no function calls)\n-- medium_iter: ~15ms  (ipairs iterator call per element)\n-- slow_iter:   ~25ms  (pairs + next() + type check)\n",[32,2212,2213,2218,2230,2248,2258,2272,2285,2289,2295,2299,2303,2308,2319,2329,2348,2361,2365,2371,2375,2379,2384,2395,2405,2422,2455,2459,2465,2469,2473,2478,2483,2488],{"__ignoreMap":58},[62,2214,2215],{"class":64,"line":65},[62,2216,2217],{"class":68},"-- Fastest: for i = 1, #t do (numeric loop, no function call per iteration)\n",[62,2219,2220,2222,2224,2227],{"class":64,"line":72},[62,2221,95],{"class":94},[62,2223,105],{"class":94},[62,2225,2226],{"class":98}," fast_iter",[62,2228,2229],{"class":108},"(t)\n",[62,2231,2232,2234,2237,2239,2242,2245],{"class":64,"line":78},[62,2233,172],{"class":94},[62,2235,2236],{"class":108}," n ",[62,2238,136],{"class":94},[62,2240,2241],{"class":94}," #",[62,2243,2244],{"class":108},"t  ",[62,2246,2247],{"class":68},"-- evaluate length ONCE\n",[62,2249,2250,2252,2254,2256],{"class":64,"line":85},[62,2251,172],{"class":94},[62,2253,175],{"class":108},[62,2255,136],{"class":94},[62,2257,180],{"class":121},[62,2259,2260,2262,2264,2266,2268,2270],{"class":64,"line":91},[62,2261,186],{"class":94},[62,2263,189],{"class":108},[62,2265,136],{"class":94},[62,2267,122],{"class":121},[62,2269,196],{"class":108},[62,2271,199],{"class":94},[62,2273,2274,2276,2278,2280,2282],{"class":64,"line":128},[62,2275,205],{"class":108},[62,2277,136],{"class":94},[62,2279,175],{"class":108},[62,2281,118],{"class":94},[62,2283,2284],{"class":108}," t[i]\n",[62,2286,2287],{"class":64,"line":145},[62,2288,225],{"class":94},[62,2290,2291,2293],{"class":64,"line":150},[62,2292,231],{"class":94},[62,2294,234],{"class":108},[62,2296,2297],{"class":64,"line":156},[62,2298,240],{"class":94},[62,2300,2301],{"class":64,"line":169},[62,2302,82],{"emptyLinePlaceholder":81},[62,2304,2305],{"class":64,"line":183},[62,2306,2307],{"class":68},"-- Slower: ipairs (iterator function call per iteration)\n",[62,2309,2310,2312,2314,2317],{"class":64,"line":202},[62,2311,95],{"class":94},[62,2313,105],{"class":94},[62,2315,2316],{"class":98}," medium_iter",[62,2318,2229],{"class":108},[62,2320,2321,2323,2325,2327],{"class":64,"line":222},[62,2322,172],{"class":94},[62,2324,175],{"class":108},[62,2326,136],{"class":94},[62,2328,180],{"class":121},[62,2330,2331,2333,2336,2338,2340,2343,2345],{"class":64,"line":228},[62,2332,186],{"class":94},[62,2334,2335],{"class":108}," _, v ",[62,2337,485],{"class":94},[62,2339,488],{"class":121},[62,2341,2342],{"class":108},"(t) ",[62,2344,494],{"class":94},[62,2346,2347],{"class":68},"  -- ipairs_iter function called per element\n",[62,2349,2350,2352,2354,2356,2358],{"class":64,"line":237},[62,2351,205],{"class":108},[62,2353,136],{"class":94},[62,2355,175],{"class":108},[62,2357,118],{"class":94},[62,2359,2360],{"class":108}," v\n",[62,2362,2363],{"class":64,"line":243},[62,2364,225],{"class":94},[62,2366,2367,2369],{"class":64,"line":248},[62,2368,231],{"class":94},[62,2370,234],{"class":108},[62,2372,2373],{"class":64,"line":254},[62,2374,240],{"class":94},[62,2376,2377],{"class":64,"line":266},[62,2378,82],{"emptyLinePlaceholder":81},[62,2380,2381],{"class":64,"line":277},[62,2382,2383],{"class":68},"-- Slowest for arrays: pairs (iterates hash part too, unordered)\n",[62,2385,2386,2388,2390,2393],{"class":64,"line":293},[62,2387,95],{"class":94},[62,2389,105],{"class":94},[62,2391,2392],{"class":98}," slow_iter",[62,2394,2229],{"class":108},[62,2396,2397,2399,2401,2403],{"class":64,"line":308},[62,2398,172],{"class":94},[62,2400,175],{"class":108},[62,2402,136],{"class":94},[62,2404,180],{"class":121},[62,2406,2407,2409,2411,2413,2415,2417,2419],{"class":64,"line":327},[62,2408,186],{"class":94},[62,2410,2335],{"class":108},[62,2412,485],{"class":94},[62,2414,440],{"class":121},[62,2416,2342],{"class":108},[62,2418,494],{"class":94},[62,2420,2421],{"class":68},"  -- next() called per element; visits ALL keys\n",[62,2423,2424,2427,2430,2433,2436,2439,2442,2444,2446,2448,2450,2453],{"class":64,"line":332},[62,2425,2426],{"class":94},"    if",[62,2428,2429],{"class":121}," type",[62,2431,2432],{"class":108},"(v) ",[62,2434,2435],{"class":94},"==",[62,2437,2438],{"class":514}," \"number\" ",[62,2440,2441],{"class":94},"then",[62,2443,175],{"class":108},[62,2445,136],{"class":94},[62,2447,175],{"class":108},[62,2449,118],{"class":94},[62,2451,2452],{"class":108}," v ",[62,2454,240],{"class":94},[62,2456,2457],{"class":64,"line":339},[62,2458,225],{"class":94},[62,2460,2461,2463],{"class":64,"line":344},[62,2462,231],{"class":94},[62,2464,234],{"class":108},[62,2466,2467],{"class":64,"line":349},[62,2468,240],{"class":94},[62,2470,2471],{"class":64,"line":355},[62,2472,82],{"emptyLinePlaceholder":81},[62,2474,2475],{"class":64,"line":361},[62,2476,2477],{"class":68},"-- Benchmark (1M element array):\n",[62,2479,2480],{"class":64,"line":367},[62,2481,2482],{"class":68},"-- fast_iter:   ~5ms   (numeric loop, no function calls)\n",[62,2484,2485],{"class":64,"line":372},[62,2486,2487],{"class":68},"-- medium_iter: ~15ms  (ipairs iterator call per element)\n",[62,2489,2490],{"class":64,"line":378},[62,2491,2492],{"class":68},"-- slow_iter:   ~25ms  (pairs + next() + type check)\n",[45,2494,2496],{"id":2495},"luajit-trace-compilation-ffi","LuaJIT — Trace Compilation & FFI",[50,2498,2499,2890,2895],{"language":52},[54,2500,2502],{"className":56,"code":2501,"language":52,"meta":58,"style":58},"-- LuaJIT: drop-in replacement for Lua 5.1, 10-100x faster via JIT compilation\n-- Traces hot loops\u002Fpaths and compiles them to native machine code\n\n-- LuaJIT-specific: require(\"ffi\") — call C functions and use C types directly\n-- This gives C-level performance WITHOUT writing C bindings\n\nlocal ffi = require(\"ffi\")\n\n-- Declare C types and functions inline\nffi.cdef[[\n  typedef struct { double x, y; } point_t;\n  double sqrt(double x);\n]]\n\n-- Create C arrays (zero-overhead, no GC)\nlocal points = ffi.new(\"point_t[?]\", 1000000)  -- 1M points, 16MB, no GC tracking\nfor i = 0, 999999 do  -- C arrays are 0-indexed!\n  points[i].x = i\n  points[i].y = i * 2\nend\n\n-- Call C math functions directly (no Lua\u002FC boundary overhead)\nlocal function compute_distances(points, n)\n  local sum = 0.0\n  for i = 0, n - 1 do\n    local p = points[i]\n    sum = sum + ffi.C.sqrt(p.x * p.x + p.y * p.y)  -- direct C call\n  end\n  return sum\nend\n\n-- Benchmark: 1M points\n-- Pure Lua:   ~150ms\n-- LuaJIT FFI: ~3ms (50x faster — C array + JIT-compiled loop)\n\n-- FFI struct: avoids Lua table overhead (no metatable, no hash lookup)\n-- BUT: FFI objects are NOT garbage collected like Lua tables (cdata type)\n-- For large arrays: ffi.new allocates from C heap, not Lua GC\n\n-- FFI type declarations can be in a file loaded once:\n-- ffi.cdef is idempotent for the same declaration (but errors on re-declaration)\n",[32,2503,2504,2509,2514,2518,2523,2528,2532,2551,2555,2560,2571,2594,2613,2618,2622,2627,2656,2676,2689,2705,2709,2713,2718,2730,2741,2759,2772,2824,2828,2834,2838,2842,2847,2852,2857,2861,2866,2871,2876,2880,2885],{"__ignoreMap":58},[62,2505,2506],{"class":64,"line":65},[62,2507,2508],{"class":68},"-- LuaJIT: drop-in replacement for Lua 5.1, 10-100x faster via JIT compilation\n",[62,2510,2511],{"class":64,"line":72},[62,2512,2513],{"class":68},"-- Traces hot loops\u002Fpaths and compiles them to native machine code\n",[62,2515,2516],{"class":64,"line":78},[62,2517,82],{"emptyLinePlaceholder":81},[62,2519,2520],{"class":64,"line":85},[62,2521,2522],{"class":68},"-- LuaJIT-specific: require(\"ffi\") — call C functions and use C types directly\n",[62,2524,2525],{"class":64,"line":91},[62,2526,2527],{"class":68},"-- This gives C-level performance WITHOUT writing C bindings\n",[62,2529,2530],{"class":64,"line":128},[62,2531,82],{"emptyLinePlaceholder":81},[62,2533,2534,2536,2539,2541,2544,2546,2549],{"class":64,"line":145},[62,2535,95],{"class":94},[62,2537,2538],{"class":108}," ffi ",[62,2540,136],{"class":94},[62,2542,2543],{"class":121}," require",[62,2545,511],{"class":108},[62,2547,2548],{"class":514},"\"ffi\"",[62,2550,727],{"class":108},[62,2552,2553],{"class":64,"line":150},[62,2554,82],{"emptyLinePlaceholder":81},[62,2556,2557],{"class":64,"line":156},[62,2558,2559],{"class":68},"-- Declare C types and functions inline\n",[62,2561,2562,2565,2568],{"class":64,"line":169},[62,2563,2564],{"class":108},"ffi.",[62,2566,2567],{"class":121},"cdef",[62,2569,2570],{"class":514},"[[\n",[62,2572,2573,2576,2579,2582,2585,2588,2591],{"class":64,"line":183},[62,2574,2575],{"class":94},"  typedef",[62,2577,2578],{"class":94}," struct",[62,2580,2581],{"class":108}," { ",[62,2583,2584],{"class":94},"double",[62,2586,2587],{"class":108}," x, y; } ",[62,2589,2590],{"class":121},"point_t",[62,2592,2593],{"class":108},";\n",[62,2595,2596,2599,2602,2604,2606,2610],{"class":64,"line":202},[62,2597,2598],{"class":94},"  double",[62,2600,2601],{"class":98}," sqrt",[62,2603,511],{"class":108},[62,2605,2584],{"class":94},[62,2607,2609],{"class":2608},"sCrzJ"," x",[62,2611,2612],{"class":108},");\n",[62,2614,2615],{"class":64,"line":222},[62,2616,2617],{"class":514},"]]\n",[62,2619,2620],{"class":64,"line":228},[62,2621,82],{"emptyLinePlaceholder":81},[62,2623,2624],{"class":64,"line":237},[62,2625,2626],{"class":68},"-- Create C arrays (zero-overhead, no GC)\n",[62,2628,2629,2631,2634,2636,2639,2642,2644,2647,2649,2651,2653],{"class":64,"line":243},[62,2630,95],{"class":94},[62,2632,2633],{"class":108}," points ",[62,2635,136],{"class":94},[62,2637,2638],{"class":108}," ffi.",[62,2640,2641],{"class":121},"new",[62,2643,511],{"class":108},[62,2645,2646],{"class":514},"\"point_t[?]\"",[62,2648,604],{"class":108},[62,2650,607],{"class":121},[62,2652,1017],{"class":108},[62,2654,2655],{"class":68},"-- 1M points, 16MB, no GC tracking\n",[62,2657,2658,2660,2662,2664,2666,2668,2671,2673],{"class":64,"line":248},[62,2659,595],{"class":94},[62,2661,189],{"class":108},[62,2663,136],{"class":94},[62,2665,684],{"class":121},[62,2667,604],{"class":108},[62,2669,2670],{"class":121},"999999",[62,2672,1711],{"class":94},[62,2674,2675],{"class":68},"  -- C arrays are 0-indexed!\n",[62,2677,2678,2681,2684,2686],{"class":64,"line":254},[62,2679,2680],{"class":108},"  points[i].",[62,2682,2683],{"class":98},"x",[62,2685,102],{"class":94},[62,2687,2688],{"class":108}," i\n",[62,2690,2691,2693,2696,2698,2700,2702],{"class":64,"line":266},[62,2692,2680],{"class":108},[62,2694,2695],{"class":98},"y",[62,2697,102],{"class":94},[62,2699,189],{"class":108},[62,2701,1200],{"class":94},[62,2703,2704],{"class":121}," 2\n",[62,2706,2707],{"class":64,"line":277},[62,2708,240],{"class":94},[62,2710,2711],{"class":64,"line":293},[62,2712,82],{"emptyLinePlaceholder":81},[62,2714,2715],{"class":64,"line":308},[62,2716,2717],{"class":68},"-- Call C math functions directly (no Lua\u002FC boundary overhead)\n",[62,2719,2720,2722,2724,2727],{"class":64,"line":327},[62,2721,95],{"class":94},[62,2723,105],{"class":94},[62,2725,2726],{"class":98}," compute_distances",[62,2728,2729],{"class":108},"(points, n)\n",[62,2731,2732,2734,2736,2738],{"class":64,"line":332},[62,2733,172],{"class":94},[62,2735,175],{"class":108},[62,2737,136],{"class":94},[62,2739,2740],{"class":121}," 0.0\n",[62,2742,2743,2745,2747,2749,2751,2753,2755,2757],{"class":64,"line":339},[62,2744,186],{"class":94},[62,2746,189],{"class":108},[62,2748,136],{"class":94},[62,2750,684],{"class":121},[62,2752,196],{"class":108},[62,2754,1652],{"class":94},[62,2756,122],{"class":121},[62,2758,610],{"class":94},[62,2760,2761,2764,2767,2769],{"class":64,"line":344},[62,2762,2763],{"class":94},"    local",[62,2765,2766],{"class":108}," p ",[62,2768,136],{"class":94},[62,2770,2771],{"class":108}," points[i]\n",[62,2773,2774,2776,2778,2780,2782,2784,2787,2790,2793,2796,2798,2801,2804,2806,2809,2811,2813,2815,2817,2819,2821],{"class":64,"line":349},[62,2775,205],{"class":108},[62,2777,136],{"class":94},[62,2779,175],{"class":108},[62,2781,118],{"class":94},[62,2783,2638],{"class":108},[62,2785,2786],{"class":98},"C",[62,2788,2789],{"class":108},".",[62,2791,2792],{"class":121},"sqrt",[62,2794,2795],{"class":108},"(p.",[62,2797,2683],{"class":98},[62,2799,2800],{"class":94}," *",[62,2802,2803],{"class":108}," p.",[62,2805,2683],{"class":98},[62,2807,2808],{"class":94}," +",[62,2810,2803],{"class":108},[62,2812,2695],{"class":98},[62,2814,2800],{"class":94},[62,2816,2803],{"class":108},[62,2818,2695],{"class":98},[62,2820,1017],{"class":108},[62,2822,2823],{"class":68},"-- direct C call\n",[62,2825,2826],{"class":64,"line":355},[62,2827,225],{"class":94},[62,2829,2830,2832],{"class":64,"line":361},[62,2831,231],{"class":94},[62,2833,234],{"class":108},[62,2835,2836],{"class":64,"line":367},[62,2837,240],{"class":94},[62,2839,2840],{"class":64,"line":372},[62,2841,82],{"emptyLinePlaceholder":81},[62,2843,2844],{"class":64,"line":378},[62,2845,2846],{"class":68},"-- Benchmark: 1M points\n",[62,2848,2849],{"class":64,"line":391},[62,2850,2851],{"class":68},"-- Pure Lua:   ~150ms\n",[62,2853,2854],{"class":64,"line":404},[62,2855,2856],{"class":68},"-- LuaJIT FFI: ~3ms (50x faster — C array + JIT-compiled loop)\n",[62,2858,2859],{"class":64,"line":417},[62,2860,82],{"emptyLinePlaceholder":81},[62,2862,2863],{"class":64,"line":430},[62,2864,2865],{"class":68},"-- FFI struct: avoids Lua table overhead (no metatable, no hash lookup)\n",[62,2867,2868],{"class":64,"line":446},[62,2869,2870],{"class":68},"-- BUT: FFI objects are NOT garbage collected like Lua tables (cdata type)\n",[62,2872,2873],{"class":64,"line":451},[62,2874,2875],{"class":68},"-- For large arrays: ffi.new allocates from C heap, not Lua GC\n",[62,2877,2878],{"class":64,"line":464},[62,2879,82],{"emptyLinePlaceholder":81},[62,2881,2882],{"class":64,"line":477},[62,2883,2884],{"class":68},"-- FFI type declarations can be in a file loaded once:\n",[62,2886,2887],{"class":64,"line":500},[62,2888,2889],{"class":68},"-- ffi.cdef is idempotent for the same declaration (but errors on re-declaration)\n",[2891,2892,2894],"h3",{"id":2893},"luajit-performance-pitfalls","LuaJIT Performance Pitfalls",[50,2896,2897,2973,2977],{"language":52},[54,2898,2900],{"className":56,"code":2899,"language":52,"meta":58,"style":58},"-- 1. Trace abort: if the JIT can't compile a loop (too complex, polymorphic),\n--    it falls back to the interpreter (10x slower)\n--    Common causes: too many types in one variable, varargs, complex closures\n\n-- 2. Math.random in LuaJIT is different from standard Lua (different PRNG)\n--    LuaJIT: Mersenne Twister; standard Lua: platform-dependent\n\n-- 3. string.format in LuaJIT uses the C implementation (fast but different float formatting)\n--    LuaJIT: string.format(\"%.17g\", 3.14) may differ slightly from PUC Lua\n\n-- 4. FFI boundary: calling Lua from C (callbacks) is slow (creates C closures)\n--    Calling C from Lua (ffi.C.*) is fast — use that direction\n\n-- 5. JIT compilation is disabled inside pcall\u002Fxpcall (trace can't cross pcall)\n--    For hot loops: don't wrap in pcall (or accept interpreter speed)\n",[32,2901,2902,2907,2912,2917,2921,2926,2931,2935,2940,2945,2949,2954,2959,2963,2968],{"__ignoreMap":58},[62,2903,2904],{"class":64,"line":65},[62,2905,2906],{"class":68},"-- 1. Trace abort: if the JIT can't compile a loop (too complex, polymorphic),\n",[62,2908,2909],{"class":64,"line":72},[62,2910,2911],{"class":68},"--    it falls back to the interpreter (10x slower)\n",[62,2913,2914],{"class":64,"line":78},[62,2915,2916],{"class":68},"--    Common causes: too many types in one variable, varargs, complex closures\n",[62,2918,2919],{"class":64,"line":85},[62,2920,82],{"emptyLinePlaceholder":81},[62,2922,2923],{"class":64,"line":91},[62,2924,2925],{"class":68},"-- 2. Math.random in LuaJIT is different from standard Lua (different PRNG)\n",[62,2927,2928],{"class":64,"line":128},[62,2929,2930],{"class":68},"--    LuaJIT: Mersenne Twister; standard Lua: platform-dependent\n",[62,2932,2933],{"class":64,"line":145},[62,2934,82],{"emptyLinePlaceholder":81},[62,2936,2937],{"class":64,"line":150},[62,2938,2939],{"class":68},"-- 3. string.format in LuaJIT uses the C implementation (fast but different float formatting)\n",[62,2941,2942],{"class":64,"line":156},[62,2943,2944],{"class":68},"--    LuaJIT: string.format(\"%.17g\", 3.14) may differ slightly from PUC Lua\n",[62,2946,2947],{"class":64,"line":169},[62,2948,82],{"emptyLinePlaceholder":81},[62,2950,2951],{"class":64,"line":183},[62,2952,2953],{"class":68},"-- 4. FFI boundary: calling Lua from C (callbacks) is slow (creates C closures)\n",[62,2955,2956],{"class":64,"line":202},[62,2957,2958],{"class":68},"--    Calling C from Lua (ffi.C.*) is fast — use that direction\n",[62,2960,2961],{"class":64,"line":222},[62,2962,82],{"emptyLinePlaceholder":81},[62,2964,2965],{"class":64,"line":228},[62,2966,2967],{"class":68},"-- 5. JIT compilation is disabled inside pcall\u002Fxpcall (trace can't cross pcall)\n",[62,2969,2970],{"class":64,"line":237},[62,2971,2972],{"class":68},"--    For hot loops: don't wrap in pcall (or accept interpreter speed)\n",[45,2974,2976],{"id":2975},"object-pool-for-hot-paths","Object Pool for Hot Paths",[50,2978,2979,3436,3440,3454,3470,3488,3507,3511,3530,3536,3550,3554],{"language":52},[54,2980,2982],{"className":56,"code":2981,"language":52,"meta":58,"style":58},"-- When creating and discarding objects in a hot loop, pool them to avoid GC pressure\n-- (see chapter 05 for the full Pool implementation)\n\nlocal Pool = {}\nPool.__index = Pool\nfunction Pool.new(factory, reset, max)\n  return setmetatable({free = {}, factory = factory, reset = reset, max = max or 100}, Pool)\nend\nfunction Pool:acquire()\n  if #self.free > 0 then return table.remove(self.free) end\n  return self.factory()\nend\nfunction Pool:release(obj)\n  if self.reset then self.reset(obj) end\n  if #self.free \u003C self.max then self.free[#self.free + 1] = obj end\nend\n\n-- Usage: pool of string builders (tables) in a serialization loop\nlocal sb_pool = Pool.new(\n  function() return {parts = {}} end,\n  function(sb) sb.parts = {} end,\n  50\n)\n\nlocal function serialize_batch(items)\n  local sb = sb_pool:acquire()\n  for i, item in ipairs(items) do\n    sb.parts[i] = tostring(item)\n  end\n  local result = table.concat(sb.parts, \",\")\n  sb_pool:release(sb)  -- return to pool, no GC\n  return result\nend\n",[32,2983,2984,2989,2994,2998,3009,3022,3036,3074,3078,3092,3133,3147,3151,3165,3189,3243,3247,3251,3256,3273,3294,3313,3318,3322,3326,3337,3355,3369,3386,3390,3411,3426,3432],{"__ignoreMap":58},[62,2985,2986],{"class":64,"line":65},[62,2987,2988],{"class":68},"-- When creating and discarding objects in a hot loop, pool them to avoid GC pressure\n",[62,2990,2991],{"class":64,"line":72},[62,2992,2993],{"class":68},"-- (see chapter 05 for the full Pool implementation)\n",[62,2995,2996],{"class":64,"line":78},[62,2997,82],{"emptyLinePlaceholder":81},[62,2999,3000,3002,3005,3007],{"class":64,"line":85},[62,3001,95],{"class":94},[62,3003,3004],{"class":108}," Pool ",[62,3006,136],{"class":94},[62,3008,474],{"class":108},[62,3010,3011,3014,3017,3019],{"class":64,"line":91},[62,3012,3013],{"class":108},"Pool.",[62,3015,3016],{"class":98},"__index",[62,3018,102],{"class":94},[62,3020,3021],{"class":108}," Pool\n",[62,3023,3024,3026,3029,3031,3033],{"class":64,"line":128},[62,3025,1191],{"class":94},[62,3027,3028],{"class":98}," Pool",[62,3030,2789],{"class":108},[62,3032,2641],{"class":98},[62,3034,3035],{"class":108},"(factory, reset, max)\n",[62,3037,3038,3040,3043,3046,3048,3051,3053,3056,3058,3061,3063,3066,3068,3071],{"class":64,"line":145},[62,3039,231],{"class":94},[62,3041,3042],{"class":121}," setmetatable",[62,3044,3045],{"class":108},"({free ",[62,3047,136],{"class":94},[62,3049,3050],{"class":108}," {}, factory ",[62,3052,136],{"class":94},[62,3054,3055],{"class":108}," factory, reset ",[62,3057,136],{"class":94},[62,3059,3060],{"class":108}," reset, max ",[62,3062,136],{"class":94},[62,3064,3065],{"class":108}," max ",[62,3067,1814],{"class":94},[62,3069,3070],{"class":121}," 100",[62,3072,3073],{"class":108},"}, Pool)\n",[62,3075,3076],{"class":64,"line":150},[62,3077,240],{"class":94},[62,3079,3080,3082,3084,3087,3090],{"class":64,"line":156},[62,3081,1191],{"class":94},[62,3083,3028],{"class":98},[62,3085,3086],{"class":108},":",[62,3088,3089],{"class":98},"acquire",[62,3091,1612],{"class":108},[62,3093,3094,3097,3099,3102,3104,3107,3110,3112,3115,3118,3121,3123,3125,3127,3129,3131],{"class":64,"line":169},[62,3095,3096],{"class":94},"  if",[62,3098,2241],{"class":94},[62,3100,3101],{"class":121},"self",[62,3103,2789],{"class":108},[62,3105,3106],{"class":98},"free",[62,3108,3109],{"class":94}," >",[62,3111,684],{"class":121},[62,3113,3114],{"class":94}," then",[62,3116,3117],{"class":94}," return",[62,3119,3120],{"class":121}," table.remove",[62,3122,511],{"class":108},[62,3124,3101],{"class":121},[62,3126,2789],{"class":108},[62,3128,3106],{"class":98},[62,3130,1545],{"class":108},[62,3132,240],{"class":94},[62,3134,3135,3137,3140,3142,3145],{"class":64,"line":183},[62,3136,231],{"class":94},[62,3138,3139],{"class":121}," self",[62,3141,2789],{"class":108},[62,3143,3144],{"class":121},"factory",[62,3146,1612],{"class":108},[62,3148,3149],{"class":64,"line":202},[62,3150,240],{"class":94},[62,3152,3153,3155,3157,3159,3162],{"class":64,"line":222},[62,3154,1191],{"class":94},[62,3156,3028],{"class":98},[62,3158,3086],{"class":108},[62,3160,3161],{"class":98},"release",[62,3163,3164],{"class":108},"(obj)\n",[62,3166,3167,3169,3171,3173,3176,3178,3180,3182,3184,3187],{"class":64,"line":228},[62,3168,3096],{"class":94},[62,3170,3139],{"class":121},[62,3172,2789],{"class":108},[62,3174,3175],{"class":98},"reset",[62,3177,3114],{"class":94},[62,3179,3139],{"class":121},[62,3181,2789],{"class":108},[62,3183,3175],{"class":121},[62,3185,3186],{"class":108},"(obj) ",[62,3188,240],{"class":94},[62,3190,3191,3193,3195,3197,3199,3201,3204,3206,3208,3211,3213,3215,3217,3219,3222,3224,3226,3228,3230,3232,3234,3236,3238,3241],{"class":64,"line":237},[62,3192,3096],{"class":94},[62,3194,2241],{"class":94},[62,3196,3101],{"class":121},[62,3198,2789],{"class":108},[62,3200,3106],{"class":98},[62,3202,3203],{"class":94}," \u003C",[62,3205,3139],{"class":121},[62,3207,2789],{"class":108},[62,3209,3210],{"class":98},"max",[62,3212,3114],{"class":94},[62,3214,3139],{"class":121},[62,3216,2789],{"class":108},[62,3218,3106],{"class":98},[62,3220,3221],{"class":108},"[",[62,3223,1074],{"class":94},[62,3225,3101],{"class":121},[62,3227,2789],{"class":108},[62,3229,3106],{"class":98},[62,3231,2808],{"class":94},[62,3233,122],{"class":121},[62,3235,2109],{"class":108},[62,3237,136],{"class":94},[62,3239,3240],{"class":108}," obj ",[62,3242,240],{"class":94},[62,3244,3245],{"class":64,"line":243},[62,3246,240],{"class":94},[62,3248,3249],{"class":64,"line":248},[62,3250,82],{"emptyLinePlaceholder":81},[62,3252,3253],{"class":64,"line":254},[62,3254,3255],{"class":68},"-- Usage: pool of string builders (tables) in a serialization loop\n",[62,3257,3258,3260,3263,3265,3268,3270],{"class":64,"line":266},[62,3259,95],{"class":94},[62,3261,3262],{"class":108}," sb_pool ",[62,3264,136],{"class":94},[62,3266,3267],{"class":108}," Pool.",[62,3269,2641],{"class":121},[62,3271,3272],{"class":108},"(\n",[62,3274,3275,3278,3280,3282,3285,3287,3290,3292],{"class":64,"line":277},[62,3276,3277],{"class":94},"  function",[62,3279,1844],{"class":108},[62,3281,112],{"class":94},[62,3283,3284],{"class":108}," {parts ",[62,3286,136],{"class":94},[62,3288,3289],{"class":108}," {}} ",[62,3291,1724],{"class":94},[62,3293,1967],{"class":108},[62,3295,3296,3298,3301,3304,3306,3309,3311],{"class":64,"line":293},[62,3297,3277],{"class":94},[62,3299,3300],{"class":108},"(sb) sb.",[62,3302,3303],{"class":98},"parts",[62,3305,102],{"class":94},[62,3307,3308],{"class":108}," {} ",[62,3310,1724],{"class":94},[62,3312,1967],{"class":108},[62,3314,3315],{"class":64,"line":308},[62,3316,3317],{"class":121},"  50\n",[62,3319,3320],{"class":64,"line":327},[62,3321,727],{"class":108},[62,3323,3324],{"class":64,"line":332},[62,3325,82],{"emptyLinePlaceholder":81},[62,3327,3328,3330,3332,3335],{"class":64,"line":339},[62,3329,95],{"class":94},[62,3331,105],{"class":94},[62,3333,3334],{"class":98}," serialize_batch",[62,3336,868],{"class":108},[62,3338,3339,3341,3344,3346,3349,3351,3353],{"class":64,"line":344},[62,3340,172],{"class":94},[62,3342,3343],{"class":108}," sb ",[62,3345,136],{"class":94},[62,3347,3348],{"class":98}," sb_pool",[62,3350,3086],{"class":108},[62,3352,3089],{"class":121},[62,3354,1612],{"class":108},[62,3356,3357,3359,3361,3363,3365,3367],{"class":64,"line":349},[62,3358,186],{"class":94},[62,3360,976],{"class":108},[62,3362,485],{"class":94},[62,3364,488],{"class":121},[62,3366,894],{"class":108},[62,3368,199],{"class":94},[62,3370,3371,3374,3376,3379,3381,3384],{"class":64,"line":355},[62,3372,3373],{"class":108},"    sb.",[62,3375,3303],{"class":98},[62,3377,3378],{"class":108},"[i] ",[62,3380,136],{"class":94},[62,3382,3383],{"class":121}," tostring",[62,3385,1307],{"class":108},[62,3387,3388],{"class":64,"line":361},[62,3389,225],{"class":94},[62,3391,3392,3394,3396,3398,3400,3403,3405,3407,3409],{"class":64,"line":367},[62,3393,172],{"class":94},[62,3395,875],{"class":108},[62,3397,136],{"class":94},[62,3399,1008],{"class":121},[62,3401,3402],{"class":108},"(sb.",[62,3404,3303],{"class":98},[62,3406,604],{"class":108},[62,3408,1014],{"class":514},[62,3410,727],{"class":108},[62,3412,3413,3416,3418,3420,3423],{"class":64,"line":372},[62,3414,3415],{"class":98},"  sb_pool",[62,3417,3086],{"class":108},[62,3419,3161],{"class":121},[62,3421,3422],{"class":108},"(sb)  ",[62,3424,3425],{"class":68},"-- return to pool, no GC\n",[62,3427,3428,3430],{"class":64,"line":378},[62,3429,231],{"class":94},[62,3431,929],{"class":108},[62,3433,3434],{"class":64,"line":391},[62,3435,240],{"class":94},[45,3437,3439],{"id":3438},"tips-tricks","💡 Tips & Tricks",[15,3441,3442,3445,3446,3449,3450,3453],{},[19,3443,3444],{},"Profile before optimizing",": 90% of time is in 10% of code. Use ",[32,3447,3448],{},"os.clock()"," benchmarks or ",[32,3451,3452],{},"debug.sethook"," profiling to find the hot path.",[15,3455,3456,3465,3466,3469],{},[19,3457,3458,3461,3462],{},[32,3459,3460],{},"t[i] = v"," is faster than ",[32,3463,3464],{},"table.insert(t, v)",": No function call, no length evaluation. Use ",[32,3467,3468],{},"t[#t + 1] = v"," for append if you can't pre-size.",[15,3471,3472,3479,3480,3483,3484,3487],{},[19,3473,3474,3475,3478],{},"Avoid ",[32,3476,3477],{},"..."," (varargs) in hot paths",": Packing varargs into a table (",[32,3481,3482],{},"{...}",") allocates. Use ",[32,3485,3486],{},"select(i, ...)"," for zero-allocation access.",[15,3489,3490,3500,3501,1943,3503,3506],{},[19,3491,3492,3493,1943,3496,3499],{},"Use ",[32,3494,3495],{},"rawget",[32,3497,3498],{},"rawset"," when you know the key exists",": Bypasses metamethod lookup (faster if no metatable, and avoids ",[32,3502,3016],{},[32,3504,3505],{},"__newindex"," overhead).",[45,3508,3510],{"id":3509},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[15,3512,3513,3519,3520,3522,3523,3526,3527,2789],{},[19,3514,3515,3518],{},[32,3516,3517],{},"#t"," evaluation is not free",": Each ",[32,3521,3517],{}," scans for a border. Cache it: ",[32,3524,3525],{},"local n = #t"," then ",[32,3528,3529],{},"for i = 1, n do",[15,3531,3532,3535],{},[19,3533,3534],{},"Closures capture upvalues, not copies",": Multiple closures sharing an upvalue cell have zero copy cost, but mutations are visible to all. This is a feature, not a bug.",[15,3537,3538,3541,3542,3545,3546,3549],{},[19,3539,3540],{},"LuaJIT trace can abort silently",": A loop that runs 100x slower than expected may have failed to compile. Use ",[32,3543,3544],{},"jit.v"," or ",[32,3547,3548],{},"jit.b"," modules to debug trace compilation.",[45,3551,3553],{"id":3552},"spot-the-bug","🧠 Spot the Bug",[50,3555,3556,3713],{"language":52},[54,3557,3559],{"className":56,"code":3558,"language":52,"meta":58,"style":58},"local function build_string(n)\n  local s = \"\"\n  for i = 1, n do\n    s = s .. tostring(i)\n  end\n  return s\nend\n\nlocal function build_string_fast(n)\n  local parts = {}\n  for i = 1, n do\n    parts[i] = tostring(i)\n  end\n  return table.concat(parts)\nend\n\n-- Benchmark with n = 100000\n-- build_string: 5 seconds\n-- build_string_fast: 5 milliseconds\n",[32,3560,3561,3572,3583,3597,3613,3617,3624,3628,3632,3643,3653,3667,3677,3681,3690,3694,3698,3703,3708],{"__ignoreMap":58},[62,3562,3563,3565,3567,3570],{"class":64,"line":65},[62,3564,95],{"class":94},[62,3566,105],{"class":94},[62,3568,3569],{"class":98}," build_string",[62,3571,166],{"class":108},[62,3573,3574,3576,3579,3581],{"class":64,"line":72},[62,3575,172],{"class":94},[62,3577,3578],{"class":108}," s ",[62,3580,136],{"class":94},[62,3582,880],{"class":514},[62,3584,3585,3587,3589,3591,3593,3595],{"class":64,"line":78},[62,3586,186],{"class":94},[62,3588,189],{"class":108},[62,3590,136],{"class":94},[62,3592,122],{"class":121},[62,3594,196],{"class":108},[62,3596,199],{"class":94},[62,3598,3599,3602,3604,3606,3608,3610],{"class":64,"line":85},[62,3600,3601],{"class":108},"    s ",[62,3603,136],{"class":94},[62,3605,3578],{"class":108},[62,3607,34],{"class":94},[62,3609,3383],{"class":121},[62,3611,3612],{"class":108},"(i)\n",[62,3614,3615],{"class":64,"line":91},[62,3616,225],{"class":94},[62,3618,3619,3621],{"class":64,"line":128},[62,3620,231],{"class":94},[62,3622,3623],{"class":108}," s\n",[62,3625,3626],{"class":64,"line":145},[62,3627,240],{"class":94},[62,3629,3630],{"class":64,"line":150},[62,3631,82],{"emptyLinePlaceholder":81},[62,3633,3634,3636,3638,3641],{"class":64,"line":156},[62,3635,95],{"class":94},[62,3637,105],{"class":94},[62,3639,3640],{"class":98}," build_string_fast",[62,3642,166],{"class":108},[62,3644,3645,3647,3649,3651],{"class":64,"line":169},[62,3646,172],{"class":94},[62,3648,965],{"class":108},[62,3650,136],{"class":94},[62,3652,474],{"class":108},[62,3654,3655,3657,3659,3661,3663,3665],{"class":64,"line":183},[62,3656,186],{"class":94},[62,3658,189],{"class":108},[62,3660,136],{"class":94},[62,3662,122],{"class":121},[62,3664,196],{"class":108},[62,3666,199],{"class":94},[62,3668,3669,3671,3673,3675],{"class":64,"line":202},[62,3670,989],{"class":108},[62,3672,136],{"class":94},[62,3674,3383],{"class":121},[62,3676,3612],{"class":108},[62,3678,3679],{"class":64,"line":222},[62,3680,225],{"class":94},[62,3682,3683,3685,3687],{"class":64,"line":228},[62,3684,231],{"class":94},[62,3686,1008],{"class":121},[62,3688,3689],{"class":108},"(parts)\n",[62,3691,3692],{"class":64,"line":237},[62,3693,240],{"class":94},[62,3695,3696],{"class":64,"line":243},[62,3697,82],{"emptyLinePlaceholder":81},[62,3699,3700],{"class":64,"line":248},[62,3701,3702],{"class":68},"-- Benchmark with n = 100000\n",[62,3704,3705],{"class":64,"line":254},[62,3706,3707],{"class":68},"-- build_string: 5 seconds\n",[62,3709,3710],{"class":64,"line":266},[62,3711,3712],{"class":68},"-- build_string_fast: 5 milliseconds\n",[3714,3715,3716,3720,3726,3732,3737,3740],"details",{},[3717,3718,3719],"summary",{},"Answer",[15,3721,3722,3723,2789],{},"The 1000x difference is explained by ",[19,3724,3725],{},"string immutability",[15,3727,3728,3731],{},[32,3729,3730],{},"s = s .. tostring(i)"," creates a NEW string each iteration. At iteration N, the string is N characters long, so the copy is O(N). Over N iterations, total work is $O(1 + 2 + 3 + ... + N) = O(N^2)$.",[15,3733,3734,3736],{},[32,3735,29],{}," accumulates strings in a table (O(1) per insert, no copying), then does a SINGLE pass to concatenate: O(N) total.",[15,3738,3739],{},"$$\\text{concat loop: } \\sum_^{N} i = \\frac{N(N+1)}{2} = O(N^2) \\quad \\text{vs} \\quad \\text{table.concat: } O(N)$$",[15,3741,3742],{},"For N=100,000: $N^2 = 10^{10}$ operations vs $N = 10^5$ operations — a 100,000x difference in raw work, observed as ~1000x in wall time (due to constant factors and allocation overhead).",[3744,3745,3746],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}",{"title":58,"searchDepth":72,"depth":72,"links":3748},[3749,3750],{"id":47,"depth":72,"text":48},{"id":542,"depth":72,"text":543},"[object Object]","md",{},"\u002Flua\u002F13-performance",{"title":5,"description":3756},{"Deep-dive into Lua performance":3757},"global vs local access cost, table pre-allocation and rehash avoidance, string interning and concatenation strategies, closure upvalue overhead, memory profiling via collectgarbage, and LuaJIT-specific optimizations (trace compilation, FFI, struct unpacking).","lua\u002F13-performance","WHF6N7VRi-S_4CHK5cABvxEgsRUMB26j_kWZ6_w-_3M",1789924650608]