ue4集合类型_UE4 垃圾回收

67c2d45627f51523e5e7cff754996556.png

UE4GC简介

UE4为我们搭建了一套UObject对象系统,并且加入了垃圾回收机制,使我们用C++进行游戏开发时更加方便,而且游戏本身也可以极大程度的避免了内存泄漏问题。

UE4采用了标记-清扫垃圾回收方式,是一种经典的垃圾回收方式。一次垃圾回收分为两个阶段。第一阶段从一个根集合出发,遍历所有可达对象,遍历完成后就能标记出可达对象和不可达对象了,这个阶段会在一帧内完成。第二阶段会渐进式的清理这些不可达对象,因为不可达的对象将永远不能被访问到,所以可以分帧清理它们,避免一下子清理很多UObject,比如map卸载时,发生明显的卡顿。

GC发生在游戏线程上,对UObject进行清理,支持多线程GC。

对GC可以设置若干参数,比如MaxObjectsInGame,规定了游戏中最大存在的UObject对象(对编辑器不生效),移动平台上默认设置了131072,当UObject数量超过这个阈值时,游戏会崩溃,其他详细参数可见UGarbageCollectionSettings,GarbageCollection.cpp,UnrealEngine.cpp中相关的属性。

下图为标记-清扫的工作原理:

ce8f9bc557781997be09c142a711e4a8.png

GC何时进行:

UE4中GC可以分为主动引发和自动引发两种方式

主动引发

可以在执行一些操作时手动调用GC,比如卸载一个资源后,立即调用一次GC进行清理。

而且方式有多种,游戏中可以调用ForceGarbageCollection来让World下次tick时进行垃圾回收。也可以直接调用CollectGarbage进行垃圾回收,引擎中大部分情况都用这种方式主动引发。

自动引发

游戏中,大部分的垃圾回收操作都是由UE4自动引发的,普通情况下不需要手动调用GC,这也是理想的GC使用方式。

当World进行tick时,会调用UEngine::ConditionalCollectGarbage()函数,函数中进行了一些判断,当满足GC条件时,才会执行GC。下面分析一下ConditionalCollectGarbage的执行逻辑。

c5ae79dcc6bf1a5a2f980b4cabe9b140.png

UE4GC流程

入口为UObjectGlobals.h中定义的CollectGarbage()函数,如下:

void CollectGarbage(EObjectFlags KeepFlags, bool bPerformFullPurge)
{
    
	// No other thread may be performing UObject operations while we're running
	AcquireGCLock();

	// Perform actual garbage collection
	CollectGarbageInternal(KeepFlags, bPerformFullPurge);

	// Other threads are free to use UObjects
	ReleaseGCLock();
}

过程包括3个部分,获取GC锁,执行CollectGarbageInternal,释放GC锁。

获取GC锁

因为GC是多线程的,因此要设置GC锁,防止其他线程做UObject相关操作,会与GC冲突,这主要用于保护异步加载过程。

一个作用为防止一个对象被加载后,存储的变量还没来得及添加引用,就被当作不可达垃圾回收掉了。如下代码就是一个例子,FGCScopeGuard起到了阻止任何GC操作的作用。

81b7c66152eec8fa6f35b21414830fe5.png

FGCSyncObject

GC锁是一个广义的概念,其实是FGCSyncObject这个单例类,其内部封装了多个用于锁和同步的变量,可以用于在GC运行时阻塞其他non-game线程,也可以在non-game线程执行关键操作时阻塞GC线程。当然,也并非所有情况都会阻塞,当不能立即获取到GC锁时各个线程也可以根据具体逻辑执行其他内容。

主要成员变量如下:

FThreadSafeCounter AsyncCounter:是一个线程安全计数器,当由线程执行关键Async操作时,会对这个值进行增减

FThreadSafeCounter GCCounter:用作GC锁,不为0表示线程已经获取了GC锁,正在执行GC

FThreadSafeCounter GCWantsToRunCounter:这个计数器表示线程意向进行GC,但尚未获取到GC锁,Async线程没有自动强制实现这个逻辑,需要我们手动实现对这个变量的支持

FCriticalSection Critical:线程执行GC相关操作的关键区的保护&#x

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值