【前言】

GC回收垃圾时会暂停所有线程,垃圾回收后再开启所有线程,如果垃圾回收的时间长,那么程序会出现明显的卡顿。这会导致游戏帧率下降,游戏在运行时可能卡卡顿顿,帧率下降。为了让整个程序运行过程始终保持顺畅,在进行对内存/GC进行优化,优化的方法分为三种:一是减少GC运行的时间;二是减少GC的运行次数;三是推迟GC运行时间。

【策略性的】

  • 对于子弹等不断重复出现消失的物体使用对象池Object Pooling管理
  • 游戏载入新场景时,显示调用GC.Collection回收垃圾(因为载入场景本身就要等待,GC运行造成卡顿也没事)
  • 使用SriptableObject(脚本化对象),其相当于资源文件,在实例化的时只是复制了引用(在实例化Prefab时是把数据复制了一遍)
  • 启用增量垃圾收集(增量垃圾收集将垃圾收集分解到若干帧中完成,避免出现尖峰,这些尖峰意味着进行垃圾收集那一帧的物理时间远远超过维持 60FPS 所需的 16 毫秒限制,这会导致游戏卡顿)
  • 不要在需要频繁调用的函数中写有会产生内存分配操作的代码,尤其是在Update中
  • 尽量为需要长时间存活的资源创建大对象。(>=85000字节的对象为大对象)
  • 减少装箱拆箱代码

【代码相关的】

  • 如果某个方法只需要在某段时间内或某个条件下重复调用,而不是一直被重复调用,使用Invoke Repeating或者Coroutine来替代Update方法。(Update会被每帧调用,即使里面只有一行代码,也会耗时的,用协程虽然也会产生内存,但好处在于之后就不会再被调用。)
  • Foreach内部有迭代器,会导致装箱操作,所以在可以确定数组大小的情况下,用for循环代替。数组可以List就不可以这样用
  • Debug.log()会消耗很多性能,游戏完成后尽量去掉无用的Debug
  • 减少Find,Component的使用,可以在Init中直接一次获取,而不是用的时候再获取。
  • 慎用单例并管理好单例,因为静态中的引用不会被释放,如果其引用的某个东西引用了一个资源,那么资源不会被释放,内存一直占着。
  • 注意协程造成的GC,协程中的yield语句本身不需要进行堆内存分配, 但由yield return带来的返回值可能需要分配堆内存,调用StartCoroutine()方法会产生少量的垃圾, 因为Unity需要创建一些类的实例用于管理协程。注意,不要让某一个协程长时间存在,因为协程只要没被释放,里面的所有变量,即使是局部变量(包括值类型),也都会在内存里
  • 使用缓存在实现变量的重复利用
void OnTriggerEnter(Collider other)
{Renderer[] allRenderers = FindObjectsOfType<Renderer>();//反复执行该方法时,每次都需要重新给数组分配内存ExampleFunction(allRenderers);
}//改进
private Renderer[] allRenderers;//定义一个类的成员变量,只会产生一个数组用来缓存,实现重复利用以减少不必须要的内存分配void Start()
{allRenderers = FindObjectsOfType<Renderer>();
}void OnTriggerEnter(Collider other)
{ExampleFunction(allRenderers);
}
  • 合理使用数据结构与算法,例如了解常用的List<T>,Array,Stack<T>,Queue<T>,Dictionary<TKey,TValue>的源码以便更合理地使用
  • 从脚本中获取材质时使用Renderer.sharedMaterial而不是Renderer.Material,后者会产生一份新的copy
  • struct中最好不要有引用类型的变量,这会使得GC会检测整个struct
  • 如果这个类被高频应用,且类中都是对字段的操作,没有引用类型,改用struct
  • 一个脚本写完后,可以看看哪些临时变量可以去除
  • 将暂时不用的以后还需要使用的物体隐藏起来而不是直接销毁
  • 大量字符串拼接的操作用StringBuilder
  • 避免频繁Instantiate来实例化GameObject,这会导致很多内存分配
  • 释放AssetBundle占用的资源
  • 尽量避免使用静态字段(静态字段所引用的对象不会被GC回收,如果该对象较大或该对象又引用了很多其他对象,那么这一系列的对象都一直存活。如果在接下来的程序中,我们不需要这些对象了,那么一直存活的这些对象会占用内存。)
  • for循环嵌套时把循环次数多的放在里面for 循环嵌套性能的比较_lengxiao_wang的博客-CSDN博客
  • 利用缓存,将需要重复调用的方法中的临时变量改为类的成员变量,例如Update要调用很多次,则需要产生很多临时变量的内存垃圾。
  • 链表重用与清除,同变量缓存类似,对链表、字典等需要反复用到的在用完时清除
  • 对具有返回值的Unity函数和第三方插件函数,返回结果时需要分配内存,同样采用变量缓存的方式定义一个变量来接收结果
void ExampleFunction()
{for(int i=0; i < myMesh.normals.Length;i++){Vector3 normal = myMesh.normals[i];}
}//改进
void ExampleFunction()
{Vector3[] meshNormals = myMesh.normals;for(int i=0; i < meshNormals.Length;i++){Vector3 normal = meshNormals[i];}
}
  • 对GameObject.name和GameObject.tag的获取会分配内存在存储返回的字符串,如果需要比较判断时,用GameObject.CompareTag()来替代
  • 对于需要在Update中但不需要每帧都运行的函数,设置定时器来保证每隔一段时间触发该函数
private float timeSinceLastCalled;
private float delay = 1f;
void Update()
{timSinceLastCalled += Time.deltaTime;if(timeSinceLastCalled > delay){ExampleGarbageGenerationFunction();timeSinceLastCalled = 0f;}
}
  • 不要在Update中频繁更新Text的内容,因为每次调用Update时都会分配新的字符串,源源不断产生垃圾,应该先检测Text的内容是否会发生变化。代码如下。
//每帧要为scoreText分配空间,仅用一次后就无用了
using UnityEngine;
using UnityEngine.UI;
using System.Collections;public class ExampleScript : MonoBehaviour {public Text scoreBoard;public int score;void Update() {string scoreText = "Score: " + score.ToString();scoreBoard.text = scoreText;}
}//改进
using UnityEngine;
using UnityEngine.UI;
using System.Collections;public class ExampleScript : MonoBehaviour {public Text scoreBoard;public string scoreText;public int score;public int oldScore;void Update() {if (score != oldScore) {scoreText = "Score: " + score.ToString();scoreBoard.text = scoreText;oldScore = score;}}
}
  • 如果要销毁一个物体,不要置为Null,而是要Destroy,然后置为Null。(因为置为Null,在C++层未销毁)

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

【资源相关的】

在复杂的大中型项目中,各种资源所占用的内存往往会达到游戏运行所占用的总体内存的70%以上。因此,资源可以直接决定项目内存占用情况,优化资源可以达到优化内存占用的目的。一般来说,游戏项目的资源主要分为以下几种:纹理 ( Texture ) , 网格 ( Mesh ) , 动画片段 ( AnimationClip ) , 音频片段 ( AudioClip ) , 材质 ( Material ) , 着色器 ( Shader ) , 字体资源 ( Font ) 以及文本资源 ( Text Asset ) 等等。其中,纹理、网格、动画片段、音频片段更容易占用更多的内存,即游戏运行时造成更多的内存开销。

  • 对纹理的优化

    • 纹理格式:RGBA32和RGBA16格式的纹理资源, 较之"硬件支持"格式, 会在加载时占据更大的CPU 耗时。ETC1 格式纹理, ETC1不带透明通道, 需要准备两个纹理 ( RGBETC1纹理+AlphaETC1纹理 )ETC2 格式纹理. 对于Android 平台,该格式仅能在OpenGLES3.0 的设备上被硬件支持。PVRTC 格式纹理. 支持iOS低端手机, 纹理尺寸必须是二次方正方形。Unity是支持软解的, 在不支持的设备上是可以运行游戏的. 软解慢又占内存。
    • 纹理尺寸:长宽分辨率为2的整数幂,便于压缩。
    • Read & Write:开启该选项将会使纹理内存增大一倍. 这个纹理既在显存上, 又在内存上, 而且还必须得是非压缩的格式。
  • 对网格的优化
    • 网格资源中含有Color 数据, Normal 数据和Tangent 数据,  这些数据的存在会增大网格资源文件大小和内存占用。Color 数据和Normal数据主要为3DMax,  Maya 等建模软件导出时设置所生成,  而Tangent一般为导入引擎时生成。一般来说,  这些数据主要为Shader 所用,  来生成较为酷炫的效果。尝试开启"Optimize Mesh Data"选项, 勾选后, 引擎在发布时会遍历所有的网格数据, 将多余数据去除, 从而降低Mesh文件大小。这里的“多余数据”是指渲染时Shader 不需要的数据。
  • 配置表
    • 如果配置表太大了,不要一次性加载到内存中,分关、分时机加载。

【Unity内存检测工具】

  • UnityProfiler、MemoryProfiler
  • 第三方工具:WeTest/UWA/Testplus

未完待续。。。

【参考】

Unity优化之GC——合理优化Unity的GC - zblade - 博客园

了解自动内存管理 - Unity 手册

https://www.yuque.com/jingangxin36/unity/gnx6ec

Unity优化之GC——合理优化Unity的GC_慕课手记

Unity内存/GC优化方法相关推荐

  1. Unity+NGUI性能优化方法总结

    原文地址:http://blog.csdn.net/zzxiang1985/article/details/43339273 一共9招. 1 资源分离打包与加载 游戏中会有很多地方使用同一份资源.比如 ...

  2. CUDA基本优化方法

    一.基于编程模型和执行模型的优化方法 1.选取合适的gridDim和blockDim blockDim最好为32的整数倍:因为执行指令的基本单位为线程束,线程束内的所有线程统一执行广播下来的命令,而线 ...

  3. Unity内存管理和GC优化

    目录 [性能优化]内存管理和GC优化 前言 内存优化思维导图 一.托管堆基础知识学习 1.1. Unity游戏运行时内存占用分以下几部分: 1.2 GC和堆内存联系 二.垃圾回收何时触发 三.GC如何 ...

  4. 45.JVM调优策略、常见问题:内存泄漏(年老代堆空间被占满、持久代被占满、堆栈溢出、线程堆栈满、系统内存被占满)优化方法:优化目标、优化GC步骤、优化总结;案例分析(公司系统参数、网上给的配置参数)

    45.JVM调优策略 45.1.常见问题 45.1.1.内存泄漏 45.1.1.1.年老代堆空间被占满 45.1.1.2.持久代被占满 45.1.1.3.堆栈溢出 45.1.1.4.线程堆栈满 45. ...

  5. Unity优化之GC——合理优化Unity的GC (难度3 推荐5)

    原文链接: http://www.cnblogs.com/zblade/p/6445578.html 最近有点繁忙,白天干活晚上抽空写点翻译,还要运动,所以翻译工作进行的有点缓慢 =.= 本文续接前面 ...

  6. 【Unity】Unity内存管理与优化(一)内存域、堆栈、垃圾回收、内存泄漏、内存碎片

    文章目录 Unity内存 内存域 - 托管域 - 本地域 - 外部库 - 跨桥操作 堆和栈 - 栈 - 堆 - 堆栈的使用 垃圾回收 - Mono内存分配过程 - 内存泄漏 - 内存碎片 - 运行时垃 ...

  7. 【Unity】Unity内存管理与优化(三)

    文章目录 Unity内存管理 大对象堆LOH(Large Object Heap) 方法调用 内存细分 分析内存 - 分析内存消耗 - 分析内存效率 内存管理性能增强 垃圾回收策略 手动JIT编译 值 ...

  8. Unity优化之GC——合理优化Unity的GC

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

  9. Unity 内存优化之理解托管堆和本机堆

    https://docs.unity3d.com/Manual/BestPracticeUnderstandingPerformanceInUnity4-1.html https://www.dazh ...

  10. Unity内存优化经验分享

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...

最新文章

  1. c语言编写系统服务程序,C语言Windows服务程序编写-ServiceMain
  2. OpenJudge计算概论-找和为K的两个元素
  3. CSP认证201612-4 压缩编码[C++题解]:区间dp、huffman树、石子合并
  4. 【行业应用】一文讲通电力数字化转型
  5. PostgreSQL学习笔记1之表定义
  6. P4981-父子【数学,树】
  7. Java 之 注释介绍
  8. java中引用类型作形参_阿花宝宝 Java基础笔记 之 引用类型作为参数
  9. atitit. js 跨界面 页面 web cs 传值方法总结
  10. 好的编码习惯是一场代码驱邪仪式
  11. 人物拼图java_JAVA实现拼图游戏
  12. 密码学与网络安全—知识点总结
  13. Real-Time Video Super-Resolution with Spatio-Temporal Networks and Motion Compensation论文解析(视频超分)
  14. UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xb5 in position 2: invalid start byte
  15. 开源协同办公软件多人在线编辑office 地址:http://www.dzzoffice.com/
  16. 什么是虚拟机?虚拟机有什么用?虚拟机的特点?
  17. unity 手机游戏优化(场景篇)
  18. 软件测试常用文档规范
  19. html的公共样式,HTML+CSS入门 CSS公共样式
  20. 好分数阅卷3.0_好分数教师版下载-好分数教师版app下载(暂未上线)_预约_飞翔下载...

热门文章

  1. sklearn神经网络/BP神经网络实现葡萄酒分类问题
  2. 银耳椰椰——Alpha冲刺Day06
  3. CUDA 8 下载——CUDA Toolkit 8.0 - Feb 2017
  4. 怎样找计算机物理地址,怎么查询电脑物理地址
  5. 安卓android百度图像识别 摄像头黑屏问题
  6. Sablog-X v2.x 任意变量覆盖漏洞
  7. 开源CRM系统国内有哪些品牌做的好?
  8. 去商场淘打折商品时,计算打折以后的价钱是件颇费脑子的事情。例如原价 ¥988,标明打 7 折,则折扣价应该是 ¥988 x 70% = ¥691.60。本题就请你写个程序替客户计算折扣价。
  9. 魔兽插件是用php吗,GitHub - robinmo/wow_addons_private_use: World Of Warcraft Addons private use 魔兽世界自用插件...
  10. Jvm面试题总结及答案 300道(2022年最新版 )