虚幻引擎的GC是追踪式、非实时、精确式,非渐近、增量回收(时间片)。

垃圾回收算法分类:

分类 项目 描述
引用计数/追踪式GC 引用计数 通过额外的计数来对单个对象的引用次数进行计算,当引用计数为零时,回收对象
  追踪式 扫描系统对象引用网络,寻找被引用的对象,留下的对象即为需要回收的垃圾对象
保守/精确 保守式 不需要额外信息来进行辅助识别指针字段,根据一些特性推断出可能为指针的区域,根据这些指针判断对象已被引用,从而释放“绝对不可能被引用”的对象,不求全部回收,但求不错删
  精确式 需要额外信息来进行辅助识别指针字段,但是能够精确识别每一个被引用的对象
实时/非实时 实时 实时GC不需要中断用户程序进行
  非实时 非实时GC会要求中断用户程序运行来进行垃圾回收
渐进/非渐进 渐进 逐步完成搜索与回收
  非渐进 一次完成搜索和回收操作

UClass包含了类的成员变量信息,类的成员变量包含了“是否是指向对象的指针”,因此具备选择精确式GC的客观条件。

利用反射系统,完成对每一个被引用的对象的定位。故采用追踪式GC。

虚幻在回收过程中,没有搬迁对象,应该是考虑到对象搬迁过程中修正指针的庞大成本。

选择了一个非实时但是渐进式的垃圾回收算法,将垃圾回收的过程分步、并行化,以削弱选择追踪式GC带来的暂停等消耗。

垃圾回收函数 CollectGarbage

  1. 锁定
  2. 回收
  3. 解锁

虚幻的GC入口是CollectGarbage()

COREUOBJECT_API void CollectGarbage(EObjectFlags KeepFlags, bool bPerformFullPurge = true);
void CollectGarbage(EObjectFlags KeepFlags, bool bPerformFullPurge)
{// No other thread may be performing UOBject operations while we're runningGGarbageCollectionGuardCritical.GCLock();// Perform actual garbage collectionCollectGarbageInternal(KeepFlags, bPerformFullPurge);// Other threads are free to use UObjectsGGarbageCollectionGuardCritical.GCUnlock();
}

锁定/解锁

借助GGarbageCollectionGuardCritical.GCLock/GCUnLock函数,在垃圾回收期间,其他线程的任何UObject操作都不会工作,从而避免出现一边回收一边操作导致各种问题。

回收

回收过程对应函数CollectGarbageInternal中的FRealtimeGC::PerfomReachablilityAnanlysis函数,可以看做两个步骤:标记和清除。不过,增加了簇和增量清除,簇是为了提高回收效率,增量清除是为了避免垃圾回收时导致的卡顿。

标记过程:全部标记为不可达,然后遍历对象引用网络来标记可达对象。

清除过程:直接检查标记,对没有被标记可达的对象,调用ConditionalBeginDestroy函数来请求删除。

标记过程的实现原理:

全部标记为不可达:虚幻引擎的MarkObjectsAsUnreachable函数就是用来标记不可达的。借助FRawObjectIterator遍历所有的UObject,然后设置标记为Unreachable即可。

MarkObjectsAsUnreachable(ObjectsToSerialize, KeepFlags);

遍历对象引用网络来标记可达对象:

FGCReferenceProcessor ReferenceProcessor;
TFastReferenceCollector<FGCReferenceProcessor, FGCCollector, FGCArrayPool> ReferenceCollector(ReferenceProcessor, FGCArrayPool::Get());
ReferenceCollector.CollectReferences(ObjectsToSerialize, bForceSingleThreaded);

这里有几个重要的对象TFastReferenceCollector、FGCReferenceProcessor、以及FGCCollector,分别介绍一下。

TFastReferenceCollector:用于可达性分析。

如果是单线程就调用ProcessObjectArray()函数,遍历UObject的记号流(token stream)来查找存在的引用,如果没有记号流,调用UClass::AssembleReferenceTokenStream()函数就是用生成记号流(token steam,其实就是记录了什么地方有UObject引用),用CLASS_TokenStreamAssembled来保存。

如果是多线程,创建几个FCollectorTask来处理,最终还是调用ProcessObjectArray()函数来处理。

UClass::AssembleReferenceTokenStream()函数

如果没有创建token stream,那么就会遍历当前UClass的所有UProperty,对每个UProperty调用EmitReferenceInfo()函数,这是一个虚函数,如果它有父类,那么就会调用父类的AssembleReferenceTokenStream()函数,并把父类添加到数组的前面,最后加上GCRT_EndOfStream到记号流中,并设置CLASS_TokenStreamAssembled来保存。

FGCReferenceProcessor

处理由TFastReferenceCollector查找得到的UObject引用。

如果Object->IsPendingKill()的返回值为true且允许引用消除,那么把Object的引用设置为NULL

否则,调用ThisThreadAtomicallyClearedRFUnreachable()清除不可达标记,标记为可达,如果这个UObject是簇的根,调用MarkReferencedClustersAsReachable函数,把当前簇引用的其他簇标记为可达。

基于簇的垃圾回收

其中跟Cluster相关的几个函数在UObjectBaseUtility中,如下图所示:

用于加速Cook后的对象的回收,所以编辑器下不会使用簇来GC。能够作为簇根的为UMaterial和UParticleSystem,基本上所有的类都可以在簇中。当垃圾回收阶段检查到一个簇根不可达,整个簇都会被回收,加速回收的效率,节省了再去处理簇的子对象的时间。

FGCCollector

继承自FReferenceCollector,HandleObjectReference()和HandleObjectReferences()都调用了FGCReferenceProcessor的HandleObjectReference()方法来进行UObject的可达性分析。

清除过程的实现原理:

为了减少卡顿,虚幻增加了增量清除的概念(IncrementalPurgeGarbage()函数),就是一次删除只占用固定的时间片,一段段进行销毁的触发。

  • 需要注意的是,由于会在两次清除时间内产生新的UObject,故在每次进入清除时,需要检查GObjCurrentPurgeObjectIndexNeedsReset,如果为true,那么重新创建一个FRawObjectIterator用于遍历所有的UObject。
  • 通过GObjCurrentPurgeObjectIndex来循环遍历所有的FUObjectItem(记录了UObject相关的信息,比如ClusterIndex,Flags等),如果对象不可达且IsReadyForFinishDestroy()为true,那么我们就调用ConditionalFinishDestroy();
  • 而如果IsReadyForFinishDestroy()为false,那么把它添加到GGCObjectPendingDestruction中去。待到下一次增量清除时,如果GGCObjectPendingDestructionCount不为0且IsReadyForFinishDestroy()为true,那么我们就调用ConditionalFinishDestroy()。
  • 当然如果有时间限制,到了时间限制,也会退出。

参考文献:

https://www.cnblogs.com/ghl_carmack/p/6112118.html

虚幻4引擎垃圾回收原理相关推荐

  1. java知识点8——垃圾回收原理和算法、通用的分代垃圾回收机制、 JVM调优和Full GC、开发中容易造成内存泄露的操作

    垃圾回收原理和算法 内存管理 Java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放. 对象空间的分配:使用new关键字创建对象即可 对象空间的释放:将对象赋值null即可 垃圾回 ...

  2. 图文结合,白话 Go 的垃圾回收原理

    前面两篇文章介绍了Go语言的内存分配策略以及Go协程动态扩充和收缩栈内存的原理,今天这篇文章我们主要来聊一下内存管理的另外一大块内容:垃圾回收. 下面首先我们会聊一下什么是GC (垃圾回收),GC的作 ...

  3. WeakHashMap垃圾回收原理

    介绍 WeakHashMap自然联想到的是HashMap.确实,WeakHashMap与HashMap一样是个散列表,存储内容也是键值对.与HashMap类似的功能就不展开了,本文重点关注在WeakH ...

  4. 图文结合,白话Go的垃圾回收原理

    前面两篇文章介绍了Go语言的内存分配策略以及Go协程动态扩充和收缩栈内存的原理,今天这篇文章我们主要来聊一下内存管理的另外一大块内容:垃圾回收. 下面首先我们会聊一下什么是GC (垃圾回收),GC的作 ...

  5. ES5-19 变量声命周期、垃圾回收原理、arguments

    变量声命周期 垃圾回收 找出不再使用的变量 释放其占用内存 固定的时间间隔运行 解除由于闭包产生的对fn AO的引用 标记清除 排除全局变量.排除闭包引用的AO中的变量 进入环境 → 离开环境 常用 ...

  6. Java中的垃圾回收原理

    用户程序(mutator)会修改还堆区中的对象集合,从存储管理器处获取空间,创建对象,还可一引入和消除对已有对象的引用. 当mutator不能"达到"某些对象的时候,这些对象就成了 ...

  7. 一文详解,jvm内存分代与垃圾回收原理

    jvm运行时数据区 Java程序启动后,本质上就是启动一个jvm进程,jvm会将自己管理的内存划分为几个区域,每个区域都有自己的用途.在程序运行时的内存区域主要可以划分为五个,分别是:方法区.堆.虚拟 ...

  8. java简述垃圾回收原理及算法_Java垃圾回收原理和算法

    ·内存管理 Java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放. 对象空间的分配:使用new关键字创建对象即可 对象空间的释放:将对象赋值null即可.垃圾回收器将负责回收所有 ...

  9. JVM之一:GC垃圾回收原理及算法分析

    导读 本人java小白一枚,写博客用意一是做一个学习总结,二是作一个分享.所写内容难免会有错误或者理解不到位的情况,恳请各位大佬不断对我提出批评,用技术吊打我,鞭笞我.拜谢~~ 一.java中的垃圾 ...

  10. python内存管理垃圾回收原理

    "  引用计数器 为主, 标记清除 和 分代回收 为

最新文章

  1. Rancher 推出 k3OS,业界首个 Kubernetes 操作系统
  2. 那个能力很强的程序员学历造假,被辞退了!
  3. Android下的Junit测试
  4. IIS的安全配置策略
  5. 图像处理方面的sci期刊_【IEEE Access 】【一年收录1.5w篇文章的SCI】一个月录用案例...
  6. 对付ring0 inline hook
  7. python如何提高程序可读性_Python规范:提高可读性
  8. Linux系统的查看系统信息和常用监控命令
  9. 开机出现grub rescue
  10. 图片识别引擎-识图引擎搜集~
  11. 《C陷阱与缺陷》读书笔记与总结
  12. 花西子背后的那个男人和他的五篇笔记
  13. C语言中pow函数的使用
  14. 云服务器ubuntu建网站,云服务器ubuntu建网站
  15. Dev-C++5.11游戏创作之简易游戏(之前的登录软件与跑酷程序的结合)
  16. HCIA网络基础17-HDLC和PPP
  17. CentOS7 安装学之思开源考试系统Mysql版
  18. 简单的将linux二进制程序、资源打包成rpm
  19. java语言编程入门
  20. 你知道吗?申报深圳市专精特新企业必须先申报创新型中小企业!

热门文章

  1. 【AllenNLP入门教程】: 1、基于Allennlp2.4版本的文本分类
  2. js Unicode编码
  3. qq空间尾巴怎么修改成别的机型
  4. 用matlab求众数,Matlab求方差,均值,均方差,协方差的函数
  5. SPSS基础教程:统计分析前的准备
  6. halcon实现直方图匹配(直方图规定化)
  7. 【华为云技术分享】“技术-经济范式”视角下的开源软件演进剖析-part 2
  8. 十三种常用的数据挖掘的技术
  9. 产品读书《麦肯锡方法》
  10. 拆弹实验-phase_2