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

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

2026-09-21 18:14 作者:996 技术组 0 阅读 性能调优

实战应用:用在哪里

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 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →

玩法策划沙巴克税收

【玩法策划】沙城税务官:税收分配与廉政度的玩法设计

实战应用:用在哪里 沙巴克占领行会坐收税收却只进不出,非占领行会的玩家心里不平衡。税务官玩法把税收做成明账:占领行会对摆摊与…

2026-09-23 01:24 996 技术组 · 0 阅读
玩法策划比武社交

【玩法策划】比武招亲:比武切磋与社交绑定的玩法设计

实战应用:用在哪里 高端玩家婚姻系统只有仪式没有过程,社交绑定缺一个高光事件。比武招亲做成擂台玩法:擂主设擂摆彩头,攻擂者报…

2026-09-23 01:24 996 技术组 · 0 阅读
案例复盘限时礼包日期

【案例复盘】限时礼包少发一天的事故复盘

实战应用:用在哪里 开服七日限时礼包发到第六天断了粮,9 月 1 日当天领奖按钮灰的,投诉当天破千。事故根因是一条数字日期循…

2026-09-23 01:24 996 技术组 · 0 阅读
网络通信心跳假在线

【网络通信】心跳探测:半开连接的主动识别

实战应用:用在哪里 玩家拔线不退游戏,连接半开着,人不在指令也没有,在线数虚高,容量预案被假数据带着跑。心跳探测给每个在线玩…

2026-09-23 01:24 996 技术组 · 0 阅读
运维发布发布日历

【运维发布】发布日历:全月变更的集中排期

实战应用:用在哪里 周三发了合成系统补丁,周四又改强化概率,两条变更叠加后玩家分不清是哪个改出来的。发布日历把全月变更集中排…

2026-09-23 01:24 996 技术组 · 0 阅读
Lua实战滑动窗口计数

【Lua实战】时间窗口计数:滑动窗口的环形数组实现

实战应用:用在哪里 容量预案需要知道滚动一小时的副本进入峰值,而不是全天累计。滑动窗口用 60 个槽位每槽记一分钟的进入数,…

2026-09-23 01:24 996 技术组 · 0 阅读