每天一点点----项目中關鍵字 “ collectgarbage”

本文介绍Lua中的内存管理方法,特别是如何使用collectgarbage函数来控制垃圾回收,避免内存泄漏,并提供了一些具体的实践案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


function __G__TRACKBACK__(msg)
    print("----------------------------------------")
    print("LUA ERROR: " .. tostring(msg) .. "\n")
    -- print(debug.traceback())
    print("----------------------------------------")
end

local function main()
-- avoid memory leak
    collectgarbage("setpause", 100)
    collectgarbage("setstepmul", 5000)

    -- require('mobdebug').start()
    
    game = require("game");
    game:startup();
end

xpcall(main, __G__TRACKBACK__)


1.collectgarbage 关键词 -- 英文(garbage 垃圾 collect 收集) -- 简称 GC

collectgarbage的使用方法是collectgarbage("AAA"), AAA 不同的值代表的意思也不一样


2.為什麼下面這兩句話要放在main的開頭?

    collectgarbage("setpause", 100)
    collectgarbage("setstepmul", 5000)



網上搜索的結果展示

看两段代码 ,他们最大的区别就是一个是全局变量,另一个是本地局部变量。


跟调用test2前相比,即使Lua进行了内存回收, 内存却不会将下来 看来300K(25906K-25620K)内存由于已放到了全局函数中,是永远没有机会被回收到了!

总结一: 如何监测Lua的编程产生内存泄露:

1.       针对会产生泄露的函数,先调用collectgarbage("count"),取得最初的内存使用

2.       函数调用后, collectgarbage("collect")进行收集, 并使用collectgarbage("count")再取得当前内存, 最后记录两次的使用差

3.       从test1的收集可看到, collectgarbage("collect")被调用,并不保证一次成功, 所以, 大可以调用多次

总结二: 如何避免Lua应用中出现的内存使用过大行为:

1.       当然是代码实现不出现泄露, (废话*&%$()

2.       在测试中,其实还发现, Lua中被分配的内存,其实并不会自动回收(个人估计要么就是Lua虚拟机没有做这个事情,要么就是回收的时机是在C层), 所以, 为了避免内存过大, 应用的运行时,可能需要定期的(调用collectgarbage("collect"),又或者collectgarbage("step"))进行显式回收。


作为开发人员,我们确实有过让Lua自动内存管理。为此,有以下几种方法。

  • collectgarbage (opt [, arg])
      功能:是垃圾收集器的通用接口,用于操作垃圾收集器
      参数:
      opt:操作方法标志
      "Stop": 停止垃圾收集器。在调用重启前,收集器只会因显式的调用运行。
      "Restart": 重启垃圾收集器
      "Collect": 执行一次全垃圾收集循环
      "Count": 返回当前Lua中使用的内存量(以KB为单位)。 以 K 字节数为单位返回 Lua 使用的总内存数。 这个值有小数部分,所以只需要乘上 1024 就能得到 Lua 使用的准确字节数(除非溢出)
      "Step": 单步执行一个垃圾收集. 步长 "Size" 由参数arg指定 (大型的值需要多步才能完成),如果要准确指定步长,需要多次实验以达最优效果。如果步长完成一次收集循环,将返回True
      "Setpause": 设置 arg/100 的值作为暂定收集的时长。将 arg 设为收集器的 间歇率 。 返回 间歇率 的前一个值。
      "Setstepmul": 设置 arg/100 的值,作为步长的增幅(即新步长=旧步长*arg/100)。返回 步进倍率 的前一个值。

    例子:
    • collectgarbage("setpause", 100) 
      collectgarbage("setstepmul", 5000)



在处理 Unreal Engine 中与 `ue-shooter` 相关的游戏崩溃问题时,通常需要从多个角度进行排查和修复。以下是几个关键方向和解决方案: ### 1. **检查无缝关卡过渡中的垃圾回收问题** 如果崩溃发生在玩家进行无缝关卡过渡时(尤其是在 PIE 模式下),可能是由于垃圾回收未能正确清理前一个 `World` 导致的。确保在关卡过渡时,所有不再需要的对象和资源都被正确释放。可以参考以下代码逻辑来确保清理过程: ```cpp // 在关卡切换前手动触发垃圾回收 void UMyGameInstance::OnLevelTransition() { // 清理不再使用的对象 CollectGarbage(EObjectFlags::RF_Public); // 切换到新关卡 UGameplayStatics::OpenLevel(this, TEXT("NextLevelName")); } ``` 此外,确保 `World` 的生命周期管理正确无误,避免引用失效的 `World` 对象[^1]。 --- ### 2. **修复动画蓝图重定向导致的崩溃** 如果崩溃发生在动画蓝图重定向时,特别是当“Allow remapping to existing assets”选项启用时,应确保在重定向过程中不会对已存在的资源造成冲突。检查动画蓝图的资产引用,并确保重定向逻辑不会导致无效指针访问。以下是一个简单的资产检查逻辑: ```cpp // 检查资产是否存在 if (UObject* ExistingAsset = StaticFindObject(nullptr, ANY_PACKAGE, *AssetPath)) { // 如果资产已存在,则直接使用 NewAsset = ExistingAsset; } else { // 否则创建新资产 NewAsset = CreateNewAsset(); } ``` 确保在动画蓝图中处理资产时,所有引用都经过有效性检查[^2]。 --- ### 3. **调试绘制代码中的线程竞争问题** 如果崩溃发生在调试绘制过程中,特别是在游戏线程 (`GameThread`) 读取 `SceneProxy` 数据时,可能是由于线程竞争条件导致的。可以使用线程同步机制来解决此问题: ```cpp // 使用线程锁确保数据访问安全 FCriticalSection SceneProxyCriticalSection; void UMyDebugComponent::DrawDebugData() { FScopeLock Lock(&SceneProxyCriticalSection); // 安全地访问 SceneProxy 数据 if (SceneProxy.IsValid()) { SceneProxy->DrawDebugInfo(); } } ``` 通过引入线程锁,确保 `SceneProxy` 数据在游戏线程和渲染线程之间不会同时被访问,从而避免竞争条件[^3]。 --- ### 4. **启用发布版本中的地图覆盖功能** 如果希望在发布版本中使用命令行参数来覆盖地图,确保在 `target.cs` 文件中定义了 `UE_ALLOW_MAP_OVERRIDE_IN_SHIPPING` 宏: ```csharp public class MyGameTarget : TargetRules { public MyGameTarget(TargetInfo Target) : base(Target) { // 允许在发布版本中使用地图覆盖 UE_ALLOW_MAP_OVERRIDE_IN_SHIPPING = 1; } } ``` 这样可以通过命令行传递参数,例如 `MyGame.exe -map=MyCustomMap`,来指定启动地图,便于测试和调试特定场景[^4]。 --- ### 5. **资产从实验阶段迁移到生产阶段的处理** 如果崩溃发生在资产迁移过程中(例如从实验文件夹移动到项目文件夹),确保所有重定向器 (`redirectors`) 被正确修复。可以在编辑器中运行以下命令行来自动修复重定向器: ``` reimport ``` 此外,确保所有资产路径正确无误,避免因路径错误导致的无效引用。对于资产管理,建议使用以下结构: ``` Content/ ├── Experimental/ │ └── Assets/ └── Production/ └── Assets/ ``` 在资产准备好后,将其从 `Experimental` 移动到 `Production` 文件夹,并运行重定向器修复工具[^5]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值