[toc] UObject 对象无法被手动释放,只能被手动请求 ConditionalBeginDestroy
来完成销毁。实际上,这个操作只是设置了当前 UObject
的 RF_BeginDestroyed
为真,然后通过 SetLinker 函数将当前对象从 linker 导出表中清除。实际的销毁操作,则是在 GC 流程中进行的。 通常的 GC 主要分为以下几个部分:
- GC 对象容器 - GC 触发入口 (GabageCollection->CollectGarbage) - GC 流程
# GC 对象容器入口
1 | UCookCommandlet::ConditionalCollectGarbage() |
在这个入口里有这样一段代码
1 | int32 NumObjectsBeforeGC = GUObjectArray.GetObjectArrayNumMinusAvailable(); |
GUObjectArray
保存在 UObjectHash
的全局作用域中
1 | // Global UObject array instance |
所有存活的 Object 会存放到 FUObjectArray
的 ObjObjects
容器中
1 | /** Array of all live objects. */ |
另外,UObject 会被 Wrap 一层成 FUObjectItem
来存放到 FUObjectArray
中
1 | void FUObjectArray::AllocateUObjectIndex(UObjectBase* Object, bool bMergingThreads /*= false*/) |
# FUObjectItem
- 用来存储
UObject
的引用 - 默认会先分配
MaxChunks
个 FUObjectItem
UObjectBaseInit()->GUObjectArray.AllocateObjectPool()->ObjObjects.PreAllocate()
1 | void PreAllocate(int32 InMaxElements, bool bPreAllocateChunks) TSAN_SAFE |
由上述代码可以看出,实际上所有 Chunk
的 FUObjectItem
都是存放在一个顺序表中的 ( PreAllocatedObjects
), 而每个 Chunk 会存放对应 Chunk 的首地址,并且所有 Chunk 的元素数量是一致的
当然,如果发现 Chunk 数量不足时,会继续向后申请新的 Chunk
大概概括一下 UObjectArray 的作用: 1. 全局存储对象的作用 2. 全局对象列表管理的是 ObjectItem,而不是 Object,起到分离和记录额外信息的作用(如 GC 时,Object 并不存储 GC 信息,Object 设计时也就不用考虑 GC 问题) 3. 实现忽略 GC 功能(算一个作用吧)
# UObject 在哪里将自身引用到全局数组中?
- UOject 继承自
UObjectBase
- 构造函数调用
AddObject
AddObject
注册引用
1 | /** |