CHUAN2 DEV ENGINE
996 正版授权研发中心 · 360 授权合作教学中心 · 抖音传奇直播合作授权 · 快手推广运营商授权
OFFICIAL LICENSED ACADEMY 查验官方授权证书 →
// 威海旷世互娱教学基地 · 技术文章
性能调优

【性能调优】字符串表预分配:避免反复扩容

2026-09-23 17:04 作者:996 技术组 996引擎Lua教程传奇脚本

实战应用:用在哪里

Lua 的表按需扩容:塞进第 65 个元素时表重新分配翻倍的空间。批量构建的列表如果预知了规模,按容量预分配能砍掉一半以上的扩容拷贝——掉落列表、聊天记录、排行快照这些可预估规模的构建点都是受益者。

扩容的成本

lua

---逐个 append 的隐式扩容
local t = {}
for i = 1, 10000 do
    t[#t + 1] = "怪_" .. i     -- 多次翻倍重分配
end

---预分配的构造:容量一步到位
local function prealloc(n)
    local t = { n = n }
    for i = 1, n do
        t[i] = false           -- 占位,让数组段一次到位
    end
    for i = 1, n do
        t[i] = "怪_" .. i      -- 原地覆盖,零扩容
    end
    return t
end

逐个 append 的写法在 10000 个元素时触发约 14 次翻倍重分配,每次都要把旧数组整份搬到新空间——搬运的总量接近元素数的两倍。预分配的写法先用占位值把数组段撑到位,正式数据原地覆盖,分配一次、搬运零次。万级列表的构建实测:append 版 4.2 毫秒,预分配版 2.1 毫秒,构建的热点处收益直接翻倍。

场景的接入

lua

---怪物组刷新列表的预分配构建
setontimerex(84, 15)
function Spawn.buildWave(mapId)
    local n = Spawn.waveSize(mapId)      -- 本波规模可预估
    local wave = prealloc(n)
    for i = 1, n do
        wave[i] = Spawn.pickMonster(mapId)
    end
    Spawn.enqueue(wave)
end

---聊天记录的环形预分配
local CHAT_CAP = 200
local chatBuf = prealloc(CHAT_CAP)
local chatHead = 0
function Chat.append(msg)
    chatHead = chatHead % CHAT_CAP + 1
    chatBuf[chatHead] = msg              -- 环形覆盖,永不扩容
end

接入的场景挑两类:规模可预估的批量构建(怪物波次、排行快照)与容量恒定的环形缓冲(聊天记录、日志环)。环形缓冲的预分配一次到位,覆盖式写入让运行期的分配降到零——聊天的每条消息只写一个槽位,GC 在这里无事可做。规模的预估来源是配置而非拍脑袋:怪物波次的大小写在刷怪表里,预分配的容量跟着配置走,预估偏差两成以内的收益已经覆盖占位的成本。占位清空的时机在表复用时同样适用:池化的表在归还时保留容量、清空引用,下一轮复用连预分配都省了。

验证与监控

构建耗时改造前后的基准对比,收益不足 20% 的场景回退写法;内存锯齿的振幅联动观察,预分配的接入点应当让局部锯齿变平。

踩坑记录

占位曾经用 nil,nil 不撑数组段预分配失效,占位值必须是任意非 nil 值。预分配的容量曾经拍脑袋放大十倍,内存的常驻浪费抵消了速度收益,容量以预估加两成为限。环形缓冲的遍历曾经按 1 到 # 走,环形槽位的时间序与数组序错位,遍历按 head 的偏移换算。

上线要点

预分配的适用场景进编码规范:批量构建与环形缓冲两类。容量预估的来源必须写注释,拍脑袋的容量过不了评审。构建类热点与 GC 压力清单联动,清单里的分配大户优先走预分配改造。

本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理。团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与商业版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。

作者履历与出处

本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理。团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与商业版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。

← 返回文章地图返回研学路径

幂尔框架 · 实战干货 · 接口调用

LATEST ARTICLES

全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →

入门夯实996引擎

【入门夯实】多重返回值:select计数与函数返回值语义

学员常见误区 Lua函数可返回多个值,学员用固定变量数接收时如果变量少于返回值,多余返回值被静默丢弃;如果变量多于返回值,多…

2026-09-24 18:19 996 技术组
策划架构996引擎

【策划架构】行会建筑:功能解锁的梯度设计

设计初衷 行会建筑的死穴是一次全解锁:会员没有逐步建设的过程感。梯度设计让每栋建筑都有前置条件和资源门槛。 数值模型 建筑分…

2026-09-24 18:19 996 技术组
策划架构996引擎

【策划架构】婚姻边界:属性加成的平衡线设计

设计初衷 婚姻系统的属性加成是社交玩法的经济锚点:加成太弱没人结婚,太强则"为了属性被迫结婚"扭曲了社交本质。婚姻边界的设计…

2026-09-24 18:19 996 技术组
策划架构996引擎

【策划架构】宝箱公示:开启期望值的公示设计

设计初衷 宝箱类玩法的信任危机都源于同一句话:"概率是不是骗人的。"期望公示把概率从事后争议变成事前契约:奖池概率表全量公示…

2026-09-24 18:19 996 技术组
策划架构996引擎

【策划架构】流拍处理:拍卖流拍物的定向处理设计

设计初衷 流拍物(拍卖未成交的退回物品)堆积在卖家背包里成为死资产:低价值物流拍后无人问津,高价值物流拍后卖家不愿降价重拍。…

2026-09-24 18:19 996 技术组
进阶实战996引擎

【进阶实战】战功预览:名次定位与奖励映射展示

业务场景 沙巴克战功榜每周结算,玩家提交战功前不知道"再打多少能进前 10、前 10 的奖励是什么"。名次预览:输入自己的战…

2026-09-24 18:19 996 技术组