生命周期?内存崩溃有解!

昨天 15:3517 浏览综合
生命周期审计结果 & 整改方案 审计概况 扫描 20 个 Lua 文件,发现 11 个问题(3 高 / 5 中 / 3 低),10 个模块无问题。 高危问题(3 项) # 模块 问题  
1 main.lua:159-160 SubscribeToEvent("Update"/"KeyDown") 永不退订,全局每帧跑
2 main.lua 全局 13 个 Create*Screen 函数,零个 Destroy/Cleanup
3 AudioManager.lua:42-57 Init() 创建 9 个引擎 C++ 节点(1BGM+8SFX),无销毁逻辑,如重复调用会泄漏引擎对象
中危问题(5 项)
# 模块 问题  
4 * main.lua:74-134 15+ 模块级变量跨画面不重置(isArenaBattle_、arenaWaves_ 等脏数据风险)
5 BattleManager 战斗实例含定时器,结束后仅 currentBattle_=nil,无显式清理
6 InventoryUI:17 lastTapInfo_ 表每次单击增条目,永不清除
7 NurtureUI:34 rebuildCallback_ 闭包赋值后从不置 nil,持有外部引用
8 JobChangeUI:298-301 M.branches_、M.buildBranchCard_ 挂在模块表上从不清理
低危问题(3 项)
HandleUpdate 非战斗帧空跑(开销极小)、BattleUI callbacks 引用链、ArenaData/SocialData 模块缓存(有自限机制)。
整改方案(4 步)
步骤 1:main.lua 引入统一画面切换函数
在 main.lua 中新增 SwitchScreen(newState, createFn) 函数,所有画面切换统一走这个入口:
lua
复制
local function SwitchScreen(newState, createFn, ...)
    -- 1) 调用离开清理:根据旧 currentState_ 清理对应模块
    local old = currentState_
    if old == GameState.BATTLE then
        if currentBattle_ then BattleManager.Cleanup(currentBattle_) end
        currentBattle_ = nil
        battleEndTimer_ = 0
        battleEndResult_ = nil
    end
    if old == GameState.ARENA then
        isArenaBattle_ = false
        arenaOpponentInfo_ = nil
        arenaWaves_ = nil
        arenaStatMult_ = nil
    end
    -- 通知可清理的 UI 模块
    if NurtureUI.Teardown then NurtureUI.Teardown() end
    if JobChangeUI.Teardown then JobChangeUI.Teardown() end
    if InventoryUI.Teardown then InventoryUI.Teardown() end
    -- 2) 切换状态
    currentState_ = newState
    -- 3) 创建新画面
    createFn(...)
end
然后把现有的 currentState_ = GameState.XXX + CreateXxxScreen() 调用全部替换为 SwitchScreen(GameState.XXX, CreateXxxScreen)。
步骤 2:为有状态的 UI 模块加 Teardown()
NurtureUI.lua:
lua
复制
function M.Teardown()
    rebuildCallback_ = nil
end
JobChangeUI.lua:
lua
复制
function M.Teardown()
    M.selectedIndex_ = nil
    M.buildBranchCard_ = nil
    M.branches_ = nil
    M.baseClassId_ = nil
end
InventoryUI.lua:
lua
复制
function M.Teardown()
    lastTapInfo_ = {}
end
步骤 3:AudioManager 防重入 + Shutdown
lua
复制
function M.Init(scene)
    if bgmNode_ then return end  -- 防重入
    -- ... 现有创建逻辑 ...
end
function M.Shutdown()
    if bgmNode_ then bgmNode_:Remove(); bgmNode_ = nil end
    bgmSource_ = nil; currentBGM_ = nil
    for _, n in ipairs(sfxNodes_) do n.node:Remove() end
    sfxNodes_ = {}
end
步骤 4:BattleManager 显式清理
lua
复制
function M.Cleanup(battle)
    if not battle then return end
    battle._callbacks = nil
    battle.animTimer = 0
    battle.actionAnim = nil
end
不改动的部分
SubscribeToEvent("Update") 保留全局订阅(单入口应用,退订无实际收益,守卫条件已有)
ArenaData/SocialData 缓存保留(有 TTL 自过期,数据量小)
10 个无状态纯渲染模块不动 
我相信很多人也碰到 这个问题了发出来给大家看看!然后去研究下!试过回来留言 
来自TapTap[ID:27994320 瞎搞🦐卤虾]
2
1