当前位置: 首页 > news >正文

MyFramework:Unity ClassScope 如何自动回收临时对象

项目地址:

GitHub - ZHOURUIH/MyFramework: Unity 商用级别开发框架,经过了多年经验沉淀.一个在unity上使用的网络游戏客户端开发框架,为unity所有使用方式提供完善的封装和管理,只需要专注于游戏逻辑的编写 · GitHub

ClassScope<T>是 MyFramework 里一个很小的结构体。

它的作用很明确:

从 ClassPool 申请一个临时对象 离开 using 作用域时自动回收

它解决的不是对象池本身,而是对象池使用时最常见的问题:

申请了临时对象 但忘记归还

一、代码

ClassScope<T>的实现如下:

using System; using static FrameBaseHotFix; // 用于自动从对象池中获取一个T,不再使用时会自动释放,需要搭配using来使用,比如using(new ClassScope<T>(out var value)) public struct ClassScope<T> : IDisposable where T : ClassObject, new() { private T mValue; // 分配的对象 public ClassScope(out T value) { if (mClassPool == null) { value = new(); mValue = null; return; } value = mClassPool?.newClass<T>(true); mValue = value; } public void Dispose() { mClassPool?.destroyClass(ref mValue); } }

使用方式:

using var a = new ClassScope<SerializerRead>(out var reader); reader.init(data);

作用域结束时,Dispose()会自动执行:

mClassPool?.destroyClass(ref mValue);

对象会被归还到ClassPool


二、临时对象

ClassScope<T>适合生命周期很短的对象。

例如:

SerializerRead SerializerWrite SerializerBitRead SerializerBitWrite GameEvent 临时 LayoutInfo 临时解析对象

这类对象通常只在一个函数内使用。

函数结束后,就应该回收到对象池。

如果每次都手动写:

SerializerRead reader = mClassPool.newClass<SerializerRead>(true); // 使用 reader mClassPool.destroyClass(ref reader);

很容易在中间return、异常、分支逻辑中漏掉回收。

ClassScope<T>把这个过程收敛到using


三、onlyOnce

ClassScope<T>内部申请对象时使用:

value = mClassPool?.newClass<T>(true);

这里传入的是true

在 MyFramework 的ClassPool中,这表示临时对象。

临时对象会进入编辑器下的mInusedList

var inuseList = onlyOnce ? mInusedList : mPersistentInuseList;

如果临时对象申请后没有及时归还,ClassPool.update()会在编辑器下报错:

logError("有临时对象正在使用中,是否在申请后忘记回收到池中! \n" + stack + ", type:" + itemList.GetType());

所以ClassScope<T>不只是方便写法。

它还配合ClassPool的临时对象检查,减少忘记回收的问题。


四、Dispose 回收

ClassScope<T>是结构体,并实现IDisposable

所以可以使用:

using var a = new ClassScope<T>(out var value);

编译后等价于在作用域结束时调用:

a.Dispose();

Dispose()中执行:

mClassPool?.destroyClass(ref mValue);

destroyClass()会完成对象池回收流程:

外部引用置空 设置 PendingDestroy 调用 destroy() 移出使用列表 调用 resetProperty() 放回未使用队列

对象不是简单丢回队列。

回收前会走完整生命周期。


五、resetProperty

池化对象最终会执行:

temp.resetProperty();

这一步很关键。

临时对象复用时,不能带着上一次使用的数据。

例如SerializerRead上一次读过一段数据,如果回收前不清理,下次复用就可能残留旧状态。

ClassScope<T>自动回收对象。

ClassPool自动调用resetProperty()

两者配合后,临时对象的使用方式比较固定:

申请 使用 作用域结束 destroy resetProperty 入池

六、mClassPool 为空

构造函数里有一段特殊处理:

if (mClassPool == null) { value = new(); mValue = null; return; }

这表示框架对象池还没有初始化时,也能正常创建对象。

但这种情况下,mValuenull

后续Dispose()不会回收到对象池。

这适合框架初始化早期或单元测试场景。

对象池存在时,走池化流程。

对象池不存在时,退化成普通new


七、ClassScope2

MyFramework 里还有ClassScope2<T>

public struct ClassScope2<T> : IDisposable where T : ClassObject, new() { private T mValue0; // 分配的对象 private T mValue1; // 分配的对象 public ClassScope2(out T value0, out T value1) { if (mClassPool == null) { value0 = new(); value1 = new(); mValue0 = null; mValue1 = null; return; } value0 = mClassPool?.newClass<T>(true); value1 = mClassPool?.newClass<T>(true); mValue0 = value0; mValue1 = value1; } public void Dispose() { mClassPool?.destroyClass(ref mValue0); mClassPool?.destroyClass(ref mValue1); } }

它一次申请两个同类型临时对象。

适合需要两个临时对象配合使用的场景。

逻辑和ClassScope<T>一样:

构造时申请 Dispose 时回收

八、使用场景

MyFramework 中可以看到很多类似用法:

using var a = new ClassScope<SerializerRead>(out var reader);
using var a = new ClassScope<SerializerBitWrite>(out var writer);
using var a = new ClassScope<T>(out var param);

这些场景共同点是:

对象只在当前函数内使用 使用频率可能较高 不希望频繁 new 不希望手动写 destroyClass

例如事件对象:

using var a = new ClassScope<T>(out var param);

事件分发结束后,事件对象自动回收。

调用者不用在每个分支里手动释放。


九、和手动回收的区别

手动回收写法:

mClassPool.newClass(out SerializerRead reader, true); // 使用 reader mClassPool.destroyClass(ref reader);

问题在于回收依赖人为记住。

如果中间出现:

return;

或者:

throw;

或者复杂分支:

if (...) { return; }

就容易漏。

ClassScope<T>写法:

using var a = new ClassScope<SerializerRead>(out var reader); // 使用 reader

作用域结束自动回收。

代码更短,生命周期也更明确。


十、设计边界

ClassScope<T>适合临时对象。

不适合长期持有对象。

例如下面这种用法不合适:

using var a = new ClassScope<MyObject>(out var obj); mField = obj;

using结束后,obj会被回收到对象池。

mField会持有一个已经失效的对象。

所以ClassScope<T>的边界很明确:

对象只在当前作用域内使用 不能把对象保存到外部长期持有 不能跨帧使用 不能交给异步回调后继续使用

如果对象需要长期存在,就应该用普通newClass<T>(false)或其他生命周期管理方式。


十一、设计价值

ClassScope<T>的价值不在复杂。

它只是把对象池临时对象的生命周期固定下来:

using 开始 从 ClassPool 取对象 using 结束 自动 destroyClass

这带来几个效果:

减少手动回收代码 减少忘记归还对象 减少临时对象 GC 配合 onlyOnce 做泄漏检查 配合 resetProperty 清理状态

它适合 MyFramework 中大量短生命周期对象。


总结

ClassScope<T>的核心实现很短:

public ClassScope(out T value) { value = mClassPool?.newClass<T>(true); mValue = value; } public void Dispose() { mClassPool?.destroyClass(ref mValue); }

它利用using管理对象池临时对象。

申请时从ClassPool获取。

离开作用域时自动归还。

回收时走destroy()resetProperty()

这个设计让临时对象的使用方式更接近 C++ 里的作用域生命周期管理。

在 Unity 项目中,它适合序列化、事件、临时解析对象等高频临时对象场景。

http://www.jsqmd.com/news/1080096/

相关文章:

  • Windows 11安卓应用运行方案:WSA技术深度解析与实战指南
  • FIFA 23 Live Editor终极指南:免费开源修改器完整使用教程
  • 计算机毕业设计之奖学金评定系统
  • 计算机毕业设计之基于微信小程序的社区医院预约挂号系统的设计与实现
  • 技术实测|11大核心创新拆解:扶阳正气罐如何重构传统拔罐养生体系
  • Unity游戏自动翻译神器:XUnity.AutoTranslator完全指南
  • GPT-4o生产集成实战:流式响应、Token预估与熔断策略
  • 医院用AI管理诊疗规范文档:从找不到到秒查到的系统设计
  • 成都珍珠棉厂家怎么选?EPE内衬定制、打样验证与供应商能力分析
  • Claude语义压缩层蒸发:中间态消失后的工程应对指南
  • 大模型时代,Web安全工程师必须关注的5个新攻击面
  • 百度网盘密码查询终极指南:3分钟快速获取提取码的完整解决方案
  • MyFramework:Unity ListScope 如何减少临时 List 的 GC
  • SU(3)群特征标的点态与Lp范数估计:从Weyl公式到工程应用
  • 2025主流视频生成大模型怎么选?Seedance 2.0与竞品横向对比与报价盘点
  • 35+运维转行网络安全:告别内卷越老越吃香,附实战经验建议收藏
  • 一文读懂DolphinScheduler插件机制:如何轻松扩展任务类型与数据源
  • OpCore Simplify:重构黑苹果配置的技术框架与智能解决方案
  • 2026年苏州厂家用了这款8寸晶圆专用衬纸,良率提升0.5%!
  • 工厂短视频培训/618流量红利别浪费,工业品短视频培训巧妙借势涨曝光
  • COMSOL多孔介质二氧化碳驱油模拟
  • 计算机毕业设计之jsp基于SSM的问卷调查平台的设计与实现
  • Linux 策略路由深度解析
  • IntelliJ IDEA 2025安装包校验失败?JetBrains官网已悄然下架SHA-256旧签名证书——紧急启用新校验密钥指南(仅限48小时内有效)
  • 开封全屋定制谁家最便宜
  • Delphi 设计期窗口DPI设置
  • 关于激光管安装的相关事宜
  • 计算机毕业设计之基于SSM的锦州风味美食推广系统设计与实现
  • AI真能替代安全专家吗?聊聊AI技术在入侵检测系统中的作用与挑战
  • 亲子娱乐想让家庭再来,不能只让孩子玩、大人等