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

发布时间:2026/6/26 7:47:20
MyFramework:Unity ClassScope 如何自动回收临时对象 项目地址GitHub - ZHOURUIH/MyFramework: Unity 商用级别开发框架,经过了多年经验沉淀.一个在unity上使用的网络游戏客户端开发框架,为unity所有使用方式提供完善的封装和管理,只需要专注于游戏逻辑的编写 · GitHubClassScopeT是 MyFramework 里一个很小的结构体。它的作用很明确从 ClassPool 申请一个临时对象 离开 using 作用域时自动回收它解决的不是对象池本身而是对象池使用时最常见的问题申请了临时对象 但忘记归还一、代码ClassScopeT的实现如下using System; using static FrameBaseHotFix; // 用于自动从对象池中获取一个T,不再使用时会自动释放,需要搭配using来使用,比如using(new ClassScopeT(out var value)) public struct ClassScopeT : IDisposable where T : ClassObject, new() { private T mValue; // 分配的对象 public ClassScope(out T value) { if (mClassPool null) { value new(); mValue null; return; } value mClassPool?.newClassT(true); mValue value; } public void Dispose() { mClassPool?.destroyClass(ref mValue); } }使用方式using var a new ClassScopeSerializerRead(out var reader); reader.init(data);作用域结束时Dispose()会自动执行mClassPool?.destroyClass(ref mValue);对象会被归还到ClassPool。二、临时对象ClassScopeT适合生命周期很短的对象。例如SerializerRead SerializerWrite SerializerBitRead SerializerBitWrite GameEvent 临时 LayoutInfo 临时解析对象这类对象通常只在一个函数内使用。函数结束后就应该回收到对象池。如果每次都手动写SerializerRead reader mClassPool.newClassSerializerRead(true); // 使用 reader mClassPool.destroyClass(ref reader);很容易在中间return、异常、分支逻辑中漏掉回收。ClassScopeT把这个过程收敛到using。三、onlyOnceClassScopeT内部申请对象时使用value mClassPool?.newClassT(true);这里传入的是true。在 MyFramework 的ClassPool中这表示临时对象。临时对象会进入编辑器下的mInusedListvar inuseList onlyOnce ? mInusedList : mPersistentInuseList;如果临时对象申请后没有及时归还ClassPool.update()会在编辑器下报错logError(有临时对象正在使用中,是否在申请后忘记回收到池中! \n stack , type: itemList.GetType());所以ClassScopeT不只是方便写法。它还配合ClassPool的临时对象检查减少忘记回收的问题。四、Dispose 回收ClassScopeT是结构体并实现IDisposable。所以可以使用using var a new ClassScopeT(out var value);编译后等价于在作用域结束时调用a.Dispose();Dispose()中执行mClassPool?.destroyClass(ref mValue);destroyClass()会完成对象池回收流程外部引用置空 设置 PendingDestroy 调用 destroy() 移出使用列表 调用 resetProperty() 放回未使用队列对象不是简单丢回队列。回收前会走完整生命周期。五、resetProperty池化对象最终会执行temp.resetProperty();这一步很关键。临时对象复用时不能带着上一次使用的数据。例如SerializerRead上一次读过一段数据如果回收前不清理下次复用就可能残留旧状态。ClassScopeT自动回收对象。ClassPool自动调用resetProperty()。两者配合后临时对象的使用方式比较固定申请 使用 作用域结束 destroy resetProperty 入池六、mClassPool 为空构造函数里有一段特殊处理if (mClassPool null) { value new(); mValue null; return; }这表示框架对象池还没有初始化时也能正常创建对象。但这种情况下mValue为null。后续Dispose()不会回收到对象池。这适合框架初始化早期或单元测试场景。对象池存在时走池化流程。对象池不存在时退化成普通new。七、ClassScope2MyFramework 里还有ClassScope2Tpublic struct ClassScope2T : 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?.newClassT(true); value1 mClassPool?.newClassT(true); mValue0 value0; mValue1 value1; } public void Dispose() { mClassPool?.destroyClass(ref mValue0); mClassPool?.destroyClass(ref mValue1); } }它一次申请两个同类型临时对象。适合需要两个临时对象配合使用的场景。逻辑和ClassScopeT一样构造时申请 Dispose 时回收八、使用场景MyFramework 中可以看到很多类似用法using var a new ClassScopeSerializerRead(out var reader);using var a new ClassScopeSerializerBitWrite(out var writer);using var a new ClassScopeT(out var param);这些场景共同点是对象只在当前函数内使用 使用频率可能较高 不希望频繁 new 不希望手动写 destroyClass例如事件对象using var a new ClassScopeT(out var param);事件分发结束后事件对象自动回收。调用者不用在每个分支里手动释放。九、和手动回收的区别手动回收写法mClassPool.newClass(out SerializerRead reader, true); // 使用 reader mClassPool.destroyClass(ref reader);问题在于回收依赖人为记住。如果中间出现return;或者throw;或者复杂分支if (...) { return; }就容易漏。ClassScopeT写法using var a new ClassScopeSerializerRead(out var reader); // 使用 reader作用域结束自动回收。代码更短生命周期也更明确。十、设计边界ClassScopeT适合临时对象。不适合长期持有对象。例如下面这种用法不合适using var a new ClassScopeMyObject(out var obj); mField obj;using结束后obj会被回收到对象池。mField会持有一个已经失效的对象。所以ClassScopeT的边界很明确对象只在当前作用域内使用 不能把对象保存到外部长期持有 不能跨帧使用 不能交给异步回调后继续使用如果对象需要长期存在就应该用普通newClassT(false)或其他生命周期管理方式。十一、设计价值ClassScopeT的价值不在复杂。它只是把对象池临时对象的生命周期固定下来using 开始 从 ClassPool 取对象 using 结束 自动 destroyClass这带来几个效果减少手动回收代码 减少忘记归还对象 减少临时对象 GC 配合 onlyOnce 做泄漏检查 配合 resetProperty 清理状态它适合 MyFramework 中大量短生命周期对象。总结ClassScopeT的核心实现很短public ClassScope(out T value) { value mClassPool?.newClassT(true); mValue value; } public void Dispose() { mClassPool?.destroyClass(ref mValue); }它利用using管理对象池临时对象。申请时从ClassPool获取。离开作用域时自动归还。回收时走destroy()和resetProperty()。这个设计让临时对象的使用方式更接近 C 里的作用域生命周期管理。在 Unity 项目中它适合序列化、事件、临时解析对象等高频临时对象场景。