Unity:内存管理、GC优化

目录

一、GC简介

1. 堆内存分配和回收机制

2. 垃圾回收时的操作

3. 何时会触发垃圾回收?

4. GC操作带来的问题

二、 GC优化

1.降低GC影响的方法

2.减少内存垃圾的数量

3.造成不必要的堆内存分配的因素

《1》字符串

《2》容器类

《3》 匿名方法(Lambda)和闭包

《4》Unity函数调用

《5》装箱操作

《6》协程

《7》foreach循环

《8》函数引用

《9》 UGUI的重构

《10》语言集成查询LINQ和常量表达式

4.重构代码来减小GC的影响

5. 定期执行GC操作

三、检测堆内存分配:Unity profiler window


一、GC简介

在游戏运行的时候,数据主要存储在内存中,当游戏的数据在不需要的时候,存储当前数据的内存就可以被回收以再次使用。内存垃圾是指当前废弃数据所占用的内存,垃圾回收(GC)是指将废弃的内存重新回收再次使用的过程。

Unity中将垃圾回收当作内存管理的一部分,如果游戏中废弃数据占用内存较大,则游戏的性能会受到极大影响,此时垃圾回收会成为游戏性能的一大障碍点。

1. Unity内部有两个内存管理池:堆内存和栈内存

堆内存(heap) 主要用来存储较大的和存储时间较长的数据,主要是负责程序中的对象和数据。

栈内存(stack) 主要用来存储较小的和短暂的数据,主要是负责运行时的代码,例如函数调用。

2. 哪些数据在堆和栈上?

栈->值类型: bool byte char decimal double enum float int long sbyte short struct uint ulong ushort

堆->非空引用类型: class interface delegate object string,同时包含:
               1) 值类型数组
               2) 装箱的值类型

3. Unity托管堆简介

托管堆是由项目的脚本运行时(Scripting Runtime)——Mono或者IL2CPP内存管理器管理的一个内存片段:底层都是在C++分配内存。

        (1)   Unity Mono内存是只升不降,即使用后,哪怕空闲再多,也不会还给系统
        (2)   Il2cpp,则与一般的C++内存释放一样,释放的内存都会还给系统

4.Unity的GC机制

使用了Boehm GC算法(可以参考:https://en.wikipedia.org/wiki/Boehm_garbage_collector),是非分代(non-generational)和非压缩(non-compacting)的。

1) "非分代"是指GC执行清理操作时,必须遍历整个内存,去标记哪些没有被引用并且删除,随着内存的增长,它的性能就会降低。 目前2019版本的unity在实验分代GC算法

2) “非压缩”意味着内存中的对象不会被重新定位,去减小对象之间的内存空隙

1. 堆内存分配和回收机制

堆内存上的内存分配和存储相对而言更加复杂,主要是堆内存上可以存储短期较小的数据,也可以存储各种类型和大小的数据。其上的内存分配和回收顺序并不可控,可能会要求分配不同大小的内存单元来存储数据。

  堆上的变量在存储的时候,主要分为以下几步:

1)首先,unity检测是否有足够的闲置内存单元用来存储数据,如果有,则分配对应大小的内存单元;

2)如果没有足够的存储单元,unity会触发垃圾回收来释放不再被使用的堆内存。这步操作是一步缓慢的操作,如果垃圾回收后有足够大小的内存单元,则进行内存分配。

3)如果垃圾回收后并没有足够的内存单元,则unity会扩展堆内存的大小,这步操作会很缓慢,然后分配对应大小的内存单元给变量。

堆内存的分配有可能会变得十分缓慢,特别是在需要垃圾回收和堆内存需要扩展的情况下,通常需要减少这样的操作次数。

2. 垃圾回收时的操作

当堆内存上一个变量不再处于激活状态的时候,其所占用的内存并不会立刻被回收,不再使用的内存只会在GC的时候才会被回收。

  每次运行GC的时候,主要进行下面的操作:

1)GC会检查堆内存上的每个存储变量;

2)对每个变量会检测其引用是否处于激活状态;

3)如果变量的引用不再处于激活状态,则会被标记为可回收;

4)被标记的变量会被移除,其所占有的内存会被回收到堆内存上。

GC操作是一个极其耗费的操作,堆内存上的变量或者引用越多则其运行的操作会更多,耗费的时间越长。

注意:包含引用类型的结构体:struct是值类型的变量,但是如果struct中包含有引用类型的变量,那么GC就必须检测整个struct,大大增加GC工作量。

3. 何时会触发垃圾回收?

主要有三个操作会触发垃圾回收:

1) 在堆内存上进行内存分配操作而内存不够的时候都会触发垃圾回收来利用闲置的内存;

2) GC会自动的触发,不同平台运行频率不一样;

3) GC可以被强制执行。

特别是在堆内存上进行内存分配时内存单元不足够的时候,GC会被频繁触发,这就意味着频繁在堆内存上进行内存分配和回收会触发频繁的GC操作。

4. GC操作带来的问题

《1》.GC操作会需要大量的时间来运行,如果堆内存上有大量的变量或者引用需要检查,则检查的操作会十分缓慢,这就会使得游戏运行缓慢。

《2》GC可能会在关键时候运行,例如在CPU处于游戏的性能运行关键时刻,此时任何一个额外的操作都可能会带来极大的影响,使得游戏帧率下降。

《3》另外一个GC带来的问题是堆内存的碎片划。当一个内存单元从堆内存上分配出来,其大小取决于其存储的变量的大小。当该内存被回收到堆内存上的时候,有可能使得堆内存被分割成碎片化的单元。也就是说堆内存总体可以使用的内存单元较大,但是单独的内存单元较小,在下次内存分配的时候不能找到合适大小的存储单元,这也会触发GC操作或者堆内存扩展操作。

堆内存碎片会造成两个结果,一个是游戏占用的内存会越来越大,一个是GC会更加频繁地被触发。

二、 GC优化

1.降低GC影响的方法

《1》 减少GC的运行次数:减少托管堆内存的分配频率<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值