虚幻的垃圾回收
垃圾回收定义
垃圾回收是一种自动的内存管理机制,当程序的动态内存不再需要时,会自动予以回收,这种机制称为垃圾回收。垃圾回收可以减少程序员的负担和犯错的机会。
垃圾回收算法大致分类
- 引用计数式:通过额外的计数来实时计算单个对象的引用次数,当计数减少到0时就将对象回收。
- 追踪式:当对象达到垃圾回收条件时(内存不够或到达回收时间时)通过扫描系统中是否有对象的引用来盘对对象是否存活,然后回收对象。
- 保守式:并不能准确判断每一个对象是否存活,但是能保证在不回收存活对象的情况下回收尽可能多的无用对象。
- 精确式:在回收过程中能够准确识别每一个无用对象,通常需要额外的数据消耗(UE中的UPROPERTY)
- 搬迁式:在对象回收过程中需要移动对象在内存中的位置。
- 非搬迁式:在对象回收过程中不需要移动对象在内存中的位置。
- 实时式:不需要用户停止程序,就可以进行垃圾回收。
- 非实时式:与实时式相反,需要用户停止程序,才能进行垃圾回收。
- 渐进式:同样不需要终端程序执行,与实时式的区别在于不会立即回收对象,而是到达一定条件时才进行回收。
- 非渐进式:与渐进式的区别在于立即回收对象。
垃圾回收算法
待更新
引用计数式
引用计数是即时且渐进式的
优点:
- 能够及时回收不需要的对象。
缺点
- 修改对象时要更新旧对象的计数,增加则外的性能开销。
- 要使用额外的空间来保存计数值。
- 对于短生命周期的对象,频繁的分配和回收对象会导致内存碎片化严重。
- 可能会出现环形引用的问题(不能正确调用析构对象造成内存泄漏)。
标记清扫式
通过扫描整个系统中对象的引用来判定对象的可达性,来判断对象是否需要回收。
优点
- 不会出现环形引用问题。
- 不会有额外的性能开销。
- 与用户程序分离。
缺点
- 非实时式,需要用户停止程序才能进行垃圾回收。
- 同样可能会增加内存碎片的数量。
- 可能会对某些无用对象产生误判导致内存泄漏。
虚幻的垃圾回收方式
虚幻主要采用的是标记-清扫式,主要分为以下几个阶段:
- 第一阶段从根集合出发遍历所有可达对象,标记出可达对象和不可达对象。
- 第二阶段渐进式清理不可达对象,UE会分帧清理它们避免卡顿。
虚幻垃圾回收的原理
进行标记-清扫
从根节点集合开始递归所有可达对象,并将其标记为可达;随后将没有标记的对象(不可达对象)进行清扫。
标记过程:首先将所有对象标记为不可达,然后遍历对象引用网络并标记科大对象。
清除过程:直接检查对象标记,没有被标记的对象调用ConditionalBeginDestory函数来请求删除。
引发方式
主动引发
在卸载一个资源后会立即调用一次垃圾回收,也可以调用ForceGarbageCollection()函数主动进行垃圾回收,或直接调用CollectGarbage()函数进行垃圾回收。
自动引发
大部分情况下垃圾回收都是由虚幻自动引发的。
在world进行tick时,会调用UEngine::ConditionalGarbageCollect()函数对垃圾回收的条件进行判断,若满足回收条件则会进行垃圾回收。
基于簇的垃圾回收
虚幻引擎采用了基于簇的垃圾回收算法用于加速对象回收,作为簇的对象一般为UMaterial和UParticleSystem。当簇的根不可达后,那么整个簇都是不可达的,因而直接回收整个簇来加速垃圾回收。
后续待更新…
- 本文作者: KongXinQing
- 本文链接: https://13114987559.github.io/2023/10/15/essay/虚幻垃圾回收/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!