[Unity]⭐浅谈Unity内存优化,内存碎片?僵尸内存?以及什么是GC垃圾回收机制。

目录

🟥 一、什么是内存?

1.物理内存  

2.虚拟内存

🟧 二、Unity的内存

1.Unity的内存分类

2.游戏运行时内存占用情况

3.什么是MONO内存?

4.内存碎片、僵尸内存

🟨三、GC 垃圾回收

1.定义

2.一张图清晰得看一下流程~

3.GC的作用及步骤

4.GC存在的问题及优化策略

🟩 四、内存优化的具体建议

1.本机内存的优化

2.优化托管内存

3.图像的一些优化建议

4.UI的一些优化建议

5.其他的一些优化建议


🟥 一、什么是内存?

内存分为物理内存、虚拟内存

1.物理内存  

也就是我们真是的硬件设备,例如内存条。

****这里引出一个概念:我们需要知道,CPU访问内存是一个慢速过程。***

访问过程具体为:先访问CacheCache包含L1L2L3,也就是一级缓存,二级缓存和三级缓存,若在这些缓存里全没找到我们要的数据,再去访问内存,接着会把找到的数据存放到Cache中,完成一次操作。

Cache中没有找到数据,我们称之为Cache Miss。因此过多的Cache Miss就会导致大量的内存和CacheIO交换,浪费大量时间

因此我们需要尽量减少Cache Miss,来提高访问速度,Unity为此提出了ECS方案,它们可以将存储在内存中的不连续数据,变为连续的数据,从而降低Cache Miss的概率。

2.虚拟内存

虚拟内存是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换空间(Swap Space)。

🟧 二、Unity的内存

1.Unity的内存分类

2.游戏运行时内存占用情况

3.什么是MONO内存?

4.内存碎片、僵尸内存

这里我引用了Unity官方视频里的两张图片及以为说明

Unity官方浅谈内存管理

A.采用分区式存储管理的系统,在储存分配过程中产生的、不能供用户作业使用的主存里的小分区称成“内存碎片”。例: 现在可用内存空间为3,但是,这3个空闲空间,并不是连续的。 所以,如果程序现在申请长度为3的内存空间,同样会申请不了,会出现内存不够的情况。

B.内存泄漏(僵尸内存)产生的原因比较简单明确,就是申请的内存已经不需要再次被使用了,但是并没有归还给内存分配器(管理器)或者系统。

🟨三、GC 垃圾回收

1.定义

在Unity中,GC(Garbage Collection,垃圾回收)是一种自动内存管理机制,它负责在运行时检测和清理不再使用的对象,以便释放内存资源。

2.一张图清晰得看一下流程~

3.GC的作用及步骤

GC的主要作用在于从已用内存中找出那些不再需要使用的内存并进行释放

Mono中的GC主要有以下几个步骤:
1.停止所有需要mono内存分配的线程
2.遍历所有已用内存,找到那些不再需要使用的内存,并进行标记。
3.释放被标记的内存到空闲内存。
4.重新开始被停止的线程。

4.GC存在的问题及优化策略

🟩 四、内存优化的具体建议

1.本机内存的优化

Scene

导致Native Memory增长的原因,最常见的就是Scene。因为是c++引擎,所有的实体最终都会反映在c++上,

而不会反映在托管堆上。所以当我们构建一个GameObject的时候,实际上在Unity的底层会构建一个或多个object来存储这一个GameObject的信息(Component信息等)。所以当一个Scene里面有过多GameObject存在的时候,Native Memory就会显著的上升,甚至可能导致内存溢出

注:当我们发现Native Memory大量上升时,可以先着重检查我们的Scene

Resource

Resource文件夹里的内容被打进包的时候会做一个红黑树(R-B Tree)用做索引,即检索资源到底在什么位置。所以Resource越大,红黑树越大,它不可卸载,并在刚刚加载游戏的时候就会被一直加在内存里,极大的拖慢游戏的启动时间,因为红黑树没有分析和加载完,游戏是不会启动的,并造成持续的内存压力。所以建议不要使用Resource,使用AssetBundle

2.优化托管内存

Destroynull

Destroy,别用null,显示的调用Destroy才能真正的销毁掉。

Destroy与null
用Destroy,别用null,显示的调用Destroy才能真正的销毁掉。

减少装箱拆箱操作

例如LINQ和常量表达式以装箱的方式实现,String.Format()也常常会产生装箱操作等

对象池

虽然VM自己有内存池,但是我们还是需要自己使用内存池来管理。

闭包和匿名函数

所有的匿名函数和闭包在c#IL代码时都会被new成一个Class(匿名class),所以在里面所有函数,变量以及new的东西,都是要占内存的。

协程

协程属于闭包和匿名函数的特例,游戏开始启动一个协程直到游戏结束才释放,错误的做法。因为协程只要没被释放,里面的所有变量,即使是局部变量(包括值类型),也都会在内存里。建议用的时候才生产一个协程,不用的时候就丢掉

配置表

一个游戏,策划往往会通过excel配置很多的配置表,然后我会在游戏中加载这些excel来读取其中的数据。但是如果excel数量非常的庞大,我们最好不要一下子全丢到内存里,建议分关加载等。

单例

慎用单例,且不要什么都往里放,因为里面的变量会一直占用内存。

3.图像的一些优化建议

4.UI的一些优化建议

5.其他的一些优化建议

避免在AwakeStart中添加大量的逻辑

这对游戏启动很重要,Unity会在AwakeStart方法执行后渲染第一个画面,某些情况可能会导致启动画面或是载入画面需要花更长的时间渲染,因为你必须等每个游戏对象都完成AwakeStart的执行。同时若游戏启动时,黑屏太久,提包时可能会被退审。

数据结构

也就是ArrayListDictionary等,例如在ArrayList中使用索引的成本很低,那么就适合要经常通过索引读取的情况。而要频繁增加和移除对象时,使用Dictionary是最合适的。

感谢大家的观看,您的点赞和关注是我最大的动力

  • 34
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值