找回密码
 立即注册
查看: 283|回复: 0

Unity 内存管理的专业提示

[复制链接]
发表于 2022-11-9 13:06 | 显示全部楼层 |阅读模式
原文链接
优化是游戏开发中很重要的一部分,涉及的方面主要有 CPU,GPU,内存,网络等。
在这篇博客中,主要会写关于内存相关的优化,Unity 是如何管理内存的,以及怎样才能使游戏更高效地运行。
在深入到 Unity 之前,我们先来看一下内存是如何工作的。
操作系统会在物理内存的基础上,创建一个虚拟内存,用于程序运行。在这个抽象中,会有一些虚拟地址空间(VAS)


在内存优化上,主要考虑两部分,也就是栈(Stack)和堆(Heap)。在理解栈和堆之前,首先要理解在 Unity 中,数据的类型,可分为值类型,和引用类型。对于值类型的数值,会直接存储在栈上,并且是可以直接复制的。例如,int, float, bool, struct, Color Vector3 等。
而引用类型的数据,则是存储在堆上,但是,指向这个数据的指针,是存储在栈上的。
栈(Stack)


  • 存储值类型
  • 存储引用类型的指针
  • 由 CPU 自动管理,无须程序员关心。在函数调用时,参数将自动申请内存放入栈中,当函数结束时,这些参数又会从栈取出,释放内存,这一切操作都是自动的。
  • 栈比堆的速度快
  • 栈的容量有限,如果超过上限,则会出现栈溢出。
  • 栈的运行方式是 Last in first out。也就是后进先出,或者说先进后出。
堆(Heap)


  • 可以存储引用类型和值类型的数据
  • 由程序员手动管理
  • 内存空间不一定是连续的
  • 比栈速度慢
  • 可以扩展空间大小
接下来,我们来理解什么是 “垃圾”,以及什么是 “垃圾回收”。
垃圾

存储在栈上的一个指向堆数据的指针结束时(释放时),堆上的数据没有用了,对于这样的对象,可以理解为 “垃圾”。
垃圾回收

为了解决垃圾内存的问题,.Net 有对应的垃圾回收系统[1]
在初始化一个新的进程时,语言运行时会为该进程保留一个连续的地址空间区域。这个保留的地址空间称为托管堆。托管堆维持指向堆中下一个对象的地址指针。
从托管堆中分配内存,比非托管堆中分配内存要快。
垃圾回收系统会创建一个包含从根可访问的所有对相的图。当一个对象不在这个图中,也就是无法从根节点访问时,垃圾回收系统会将这部分内存视为垃圾,并在合适的时机释放为其分配的内存。
Unity 的内存管理系统

Unity 的内存管理分为三部分。

  • 托管内存
托管内存使用托管堆以及垃圾回收系统自动分配和释放内存,而提供这个功能的是 Mono 或 IL2CPP。在 Unity 中我们大部分时候使用的都是托管内存,所以 New 对象时,都不考虑释放,垃圾回收系统会帮我们处理掉。

  • C# 非托管内存
C#非托管内存层使你可以在编写C#代码的方便下访问本机内存层以微调存储器分配。
您可以在Unity Core API中使用Unity.CollectionsNamespace(包括NativeArray),以及Unity Collections软件包中的数据结构来访问C#非托管的内存。如果您使用Unity的 Job System 或 Brust,则必须使用C#非托管内存。

  • 原生内存
Unity用来运行引擎的c++内存。在大多数情况下,Unity用户是无法访问这些内存的,但是如果你想微调应用程序的某些方面的性能,了解这些内存是很有用的。
虽然上面的内容听起来很复杂,但其实确实不太容易理解。
托管堆由语言运行时自动管理,内存申请,内存释放,下面这个图可以方便理解。


当有一个对象结束时,垃圾回收系统会将这部分内存释放,但是不会重新排列内存。


当有更大的内存申请时,堆管理系统可能会执行下面两个操作之一

  • 运行垃圾回收,释放掉该释放的内存,看看有没有满足新内存申请大小的空间
  • 如果第一步失败了,那就扩展堆的大小
编码技巧


  • 使用 for 代替 foreach
  • 尽可能地重用 List 之类的数据结构,在重用之前调用 Clear()
  • 尽量避免 ()=> 这种匿名函数
  • 减少装箱拆箱操作(值类型转为引用,引用转为转为值类型)int value = 100;
    object obj = value;
    int num = (int)obj;
  • 对于字符串操作,可以使用 StringBuilder
  • 尽可能地缓存对象
  • 使用对象池来优化频繁创建和销毁的物品,例如游戏中的子弹
Unity 技巧


  • 使用 Addressable System 来加载和卸载对象
  • 压缩 Texture,图的大小尽量为2的次方,使用图集。
  • 没用的 Shader 功能去掉
参考资料

[1]
垃圾回收系统: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/

关注微信公众号,即时订阅博客文章




如果扫不上,可以多试一下,辛苦

另外,做一下广告,我自己开发的独立游戏《无量钓海》,欢迎大家试玩,在 TapTap,好游快爆,AppStore 可以下载

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-15 14:48 , Processed in 0.137870 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表