一. 最近看了看之前写的文章原来我以前学过啊。这次再整理一下这里推荐俩个视频挺不错。补充一些感想吧被拒绝是成长的必经路大家一起共勉。【二】虚幻引擎官方学习指导 | 详解垃圾回收内存管理机制《Unity与虚幻引擎对比》_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV17go5YQE8p/?spm_id_from333.337.search-card.all.clickvd_sourcee348f602f367e3ea8d07f6b6f0e1f654UE垃圾回收看不懂一个例子讲清楚GC机制_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1PX9cBLEJN/?spm_id_from333.1391.0.0vd_sourcee348f602f367e3ea8d07f6b6f0e1f654我很早前写的大家有兴趣可以再看一下UE 5.3 C 对垃圾回收的初步认识_ue5中如何判断utexture2d没有有被回收-CSDN博客UE5.3 C CDO的初步理解_ue cdo-CSDN博客UE C UObject 功能的初步总结结合官方文档-CSDN博客二.炒冷饭这次大道至简一些还是老规矩上官方文档Creating Objects in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer CommunityUnreal Object Handling in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer CommunityIncremental Garbage Collection in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community说实话以前官方文档看起来总有点懂一点不完全懂经过沉淀这次又能更懂一点。特此记录下自己的理解UObject的如果不加UPERPERTY宏可能会被垃圾回收。标记清理法1.标记从根集Root Set比如GameInstance、当前 World、ULevel的Actors出发沿着UPROPERTY修饰的指针成员向下遍历凡是能到达的对象都会被标记为存活。2.清扫触发时从根集合比如 World、GameInstance出发遍历所有带UPROPERTY的指针标记存活对象剩下的自动销毁。回收了UObject在堆上内存.3.措施没有被UPROPERTY修饰的UObject*裸指针无法阻止 GC 回收对象因此非持有型引用必须使用TWeakObjectPtr或TObjectPtr来兜底。去看引擎底层的类成员变量几乎都会这样写不会有裸指针。二.误区我平时经常Spawn在场景里管都没关为啥没回收这牵扯到Spawn和NewObject的区别Spawn后的Actor会自动加入到ULevel::Actors数组TArrayAActor*。而ULevel本身就是属于RootSet里的。这样就解释了为啥没回收它是自动被标记好了。三.TWeakObjectPtr这里我想说下这个一个是因为问过。还有IsValid底层是如何实现的。如果只想在类中引用UObject对象而不影响引用对象的GC可以使用 TWeakObjectPtr它不会使对象保持活动状态但在对象被销毁后当您调用这两种数据类型的 IsValid 方法时它会自动开始返回 false。弱引用就是他被回收就有人帮忙归为nullptr用isValid来判断。我自己也要改正写法。IsValid 的底层这里我先引入一个重量级的概念GUObjectArray。GUObjectArray是 Unreal Engine 中一个全局的、中心化的管理器和索引表用于跟踪内存中每一个UObject实例。你可以将它理解为 UE 对象系统的“户籍登记处”所有由引擎管理的对象其核心信息都登记在册。你猜的没错IsValid 就是要借助这个大佬。IsValid核心方式在ObjectIndex 和 ObjectSerialNumber。ObjectIndex就是GUObjectArray的下标ObjectSerialNumber是那个下标下的内容里的序列号。【具体实现在Internal_IsValid()函数中它会通过GUObjectArray.IndexToObject()获取对象并进行序列号比对。】ObjectSerialNumber(对象序列号): 这是一个与该对象绑定的、全局唯一的、递增的序列号。每当一个对象被创建并分配一个新的索引时就会生成一个新的序列号。就像你电脑上那个序列号一样全球唯一。当调用IsValid()时底层会执行以下验证逻辑通过索引取对象根据存储的ObjectIndex从全局对象表GUObjectArray中取出对应的FUObjectItem。比较序列号将存储的ObjectSerialNumber与该FUObjectItem内部的序列号进行比较。返回结果只有当两个序列号匹配时IsValid()才会返回true表示目标对象确实存在且未被销毁。顺便补充它的搭档就不展开了TObjectPtrT强引用阻止 GC用于持有对象。TWeakObjectPtrT弱引用不阻止 GC用于观察对象。四.NewObject 中的参数Outer1.一般是父亲把自己的 this 指针传给要New生出来的 子Object。让儿子指向父亲2. 目的是当Outer 为空也就是你的父皇死了(GC)你就要被连坐 GC。即使你被其他UPERPERTY()强引用也无济于事。除非AddToRoot()将子对象添加到GC根集。但这通常是不推荐的做法因为它打破了正常的生命周期管理。