大家好,今天小热关注到一个比较有意思的话题,就是关于TokenStream的问题,于是小编就整理了2个相关介绍TokenStream的解答,让我们一起看看吧。
文章目录:
一、UE4 GC机制解析(一):GC信息收集
UE4的GC信息收集机制主要在引擎加载阶段通过反射支持实现,具体解析如下:
- 信息收集流程起始:
- 始于反射支持下的初始化阶段:在UE4引擎加载过程中,信息收集流程开始。
- 调用关键函数:引擎会调用ProcessNewlyLoadedUObjects函数,该函数进而调用UClass::AssembleReferenceTokenStreams静态函数。
- 生成Token Stream:
- 非静态函数执行:AssembleReferenceTokenStream函数是非静态的,为每个被UClass修饰的类生成对应的token stream,描述GC信息。
- 防止重复生成:通过标记CLASS_TokenStreamAssembled来防止重复生成token stream。具体地,检查UClass::ClassFlags & CLASS_TokenStreamAssembled是否为1,如果是,则直接返回,避免重复遍历。
- Token Stream记录过程:
- 递归调用:由于类的继承关系类似于多叉树,递归调用AssembleReferenceTokenStream函数从多叉树的叶子结点向上回溯。
- 父类成员优先记录:在C++继承中,子类对象的内存布局将父类成员置于子类之前,因此父类成员的token stream在子类成员之前记录。
- 与C++对象内存模型和字节对齐的关系:
- UProperty替换为FProperty:在UE4中,UProperty被替换为FProperty,FProperty不再从UObject继承,而是继承自FField。
- 内存偏移量的确定:内存偏移量通过调用GetOffset_ForGC获得,实际上返回成员变量的值,表明偏移量在FProperty对象生成时就已确定。
- STRUCT_OFFSET和offsetof宏:在类型生成文件分析中,属性部分调用STRUCT_OFFSET函数,该函数内部调用offsetof宏来获取成员在struct/class内的偏移量。
- Token Stream的编码:
- 构造FGCReferenceInfo:UClass::EmitObjectReference函数构造FGCReferenceInfo,将偏移量和GC类型写入union,编码为uint32。
- 存储成员名:同时将成员名存入FGCReferenceTokenStream::TokenDebugInfo,便于检查和调试,但GC整个环节实际上不使用这些信息。
二、UE4 GC机制解析(三):标记与清除
继续深入探讨UE GC机制,分析mark和sweep的实现细节。
可达性分析
UE通过调用FRealTimeGC::PerformReachabilityAnalysis()来实现所有UObject的可达性分析。此过程中,FGCArrayStruct类的局部变量ArrayStruct被用于存储需要序列化的UObject指针,以优化内存访问。FGCObject::GGCObjectReferencer类充当UObject和FGCObject之间的桥梁,确保FGCObject子类的成员UObject在可达性分析中被正确标记为可达,避免清理。此过程虽然简单,但在UE中实现较为复杂。
MarkObjectsAsUnreachable
在分析中,UE通过MarkObjectsAsUnreachable函数根据规则标记UObject为不可达、明确可达或特殊处理,最终得到部分可达对象序列ObjectsToSerializeArrays。
PerformReachabilityAnalysisOnObjects
UE根据是否使用多线程决定调用路径,最终调用TFastReferenceCollector::ProcessObjectArray()函数,实现对可达UObject的并行处理和标记。这种实现方式依赖于UE多线程框架,性能取决于最慢线程的处理速度。同时,线程同步成本也是一个需要考虑的问题。
ProcessObjectArray()
该函数遍历ObjectsToSerialize,通过广度搜索或深度有限搜索收集可达的UObject指针,直到所有可达对象被访问。然后将新收集的对象与原ObjectsToSerialize进行交换,继续遍历下一个集合,直至所有可达对象被收集完毕。对于每个UObject,通过访问其引用收集得到的TokenStream进行深度优先搜索和广度优先搜索结合的处理,实现可达对象的全面收集。
收集不可达对象
GatherUnreachableObjects函数负责收集标记为不可达的UObject,过程涉及GUObjectArray的遍历和标记对象的收集。若在清理过程中将所有标记不可达的对象复制一份,可以直接通过memcopy操作,避免后续清理过程对原GUObjectArray的访问冲突。双Buffer机制可以在每次清理时swap,进一步优化清理过程。
不可达对象清理
UE的清理过程包括IncrementalPurgeGarbage函数,此函数在ConditionalCollectGarbage调用后执行。清理过程分为两部分:先通过UnhashUnreachableObjects函数清理UObject,随后调用FinishDestroy()通知UObject执行清理工作。清理逻辑在TickDestroyGameThreadObjects函数中实现,根据bUseTimeLimit判断是否分帧清理。最终,每个UObject将通过析构函数释放内存,清理工作可能在GameThread或异步线程中完成。至此,UE GC机制中的mark和sweep过程解析完毕。
到此,以上就是小编对于TokenStream的问题就介绍到这了,希望介绍关于TokenStream的2点解答对大家有用。
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。