插件调试技巧集锦
上线前的稳定性,靠这几套调试运营指令和 API 兜底:内存泄漏定位、CPU 性能分析、收发包统计。全部通过 SSH 到控制服执行运营指令,或用 API 封装成指令驱动。
定位内存泄漏:/check-memory-run
检查服务端脚本层内存泄漏。执行两次:第一次生成快照,第二次生成 diff。参数 serverId、useList(通常 ["tracemalloc","objreport"])、objNames(通常空)。
# 第一次(4000 为 lobby 服 ID)
curl -X POST '<控制服IP>:<端口>/check-memory-run' -H 'Content-Type: application/json' \
--data-raw '{"serverId":4000,"useList":["tracemalloc","objreport"],"objNames":[]}'
# 中间:Studio 登录一个客户端 → 完全退出
# 第二次:重复上面的 curl日志三段解读:
| 日志段 | 含义 |
|---|---|
Top 10 differences | 两次间新申请内存最多的 10 行代码(多为系统/引擎调用) |
[QA] [DIFF_MORE] | 新增且未释放的 python 对象——泄漏嫌疑 |
[QA] [DIFF_LESS] | 减少的对象,用于排除释放有延时的疑似泄漏 |
例:玩家登录再退出,若每次都 +4 BattleMob,说明该对象引用没随玩家退出释放,存在泄漏。
CPU 性能分析:/profile
测量 python 函数 CPU 占用。执行两次(bBegin:true 开始、false 结束),文件生成在服务器进程目录的 profile 子目录。
curl -X POST '<控制服IP>:<端口>/profile' -H 'Content-Type: application/json' \
--data-raw '{"serverId":4000,"bBegin":true}'
# 触发要监测的玩法后
curl -X POST '<控制服IP>:<端口>/profile' -H 'Content-Type: application/json' \
--data-raw '{"serverId":4000,"bBegin":false}'结果关键列:ncalls(调用次数)、tottime(自身耗时,不含子函数)、cumtime(含子函数总耗时)、filename:lineno(function)(代码位置)。按 tottime 排序找热点。
火焰图:StartProfile / StopProfile
API 生成 .svg 火焰图,下载后用 Chrome 打开。开销大,不宜正式服长期运行,需自行封装成运营指令驱动。
def DoProfile(second):
serverApi.StartProfile()
def finishProfile():
serverApi.StopProfile("profile_%d.svg" % int(time.time()))
comp = serverApi.GetEngineCompFactory().CreateGame(serverApi.GetLevelId())
comp.AddTimer(second, finishProfile)看火焰图只看宽度(颜色无意义):越宽=对整体性能消耗越大。竖直是调用栈,顶部是正在执行的函数。优化核心是减少调用次数、优化写法,只关注自己写的代码。
收发包统计
- 脚本层:
StartRecordEvent/StopRecordEvent,统计各脚本事件(namespace:systemName:eventName)的发送/接收次数和字节数。 - 引擎层:
StartRecordPacket/StopRecordPacket,统计各引擎消息包。注意 Apollo 客户端经 proxy 转发,NeteaseNetGameTransferPacket(转发包)数量约等于其余包总和。
用于定位流量异常大的事件/包(sendSize/recvSize 仅逻辑大小,不含加密压缩,但可作流量标的)。
Q&A
服务端 Mod 完全没生效? Studio 日志默认只拉最近一段,启动时刷屏可能把早期 traceback 冲掉。把日志窗口滚到顶部触发拉取更早日志,多半是 Mod 加载时就 traceback 了,修掉重新部署。
客户端 Mod 完全没生效? 检查 worlds/level/world_behavior_packs.json、world_resource_packs.json 存在,且里面的 uuid 与对应 behavior_packs/resource_packs 里 manifest.json 的 uuid 一致。
