unity3d代码优化标准
转载自:https://blog.csdn.net/m0_37283423/article/details/84378384
代码优化
● 尽可能使用for来代替foreach:每次foreach会产生一个Enumerator,迭代器会额外分配内存。
● 尽量避免使用Lambda表达式:存在内存泄露隐患。
● 尽量避免使用LINQ:部分功能无法在某些平台上使用,且会分配大量GC Alloc。
● 控制StartCorountine()的次数:开启一个协程,至少分配37B的内存(Coroutine类的实例 - 21B;Enumerator - 16B)。
● 使用StringBuilder来代替String进行字符串拼接:StringBuilder.Append方法在拼接字符串时,变化总是发生在同一个内存块中;而String + String + ...这种字符串拼接方式,会频繁申请内存并释放,导致GC频繁调用。
● 缓存组件:每次GetComponent均会分配一定的GC Alloc;每次获取对象名称Object.name(实际为Object.get_name())会分配39B(具体大小视实际情况而定)的堆内存。
● 避免使用开销大的函数:如GameObject.Find、GameObject.FindWithTag、Object.FindObjectOfType等查询方法。
● 使用GameObject.CompareTag代替GameObject.tag:GameObject.tag会在内部循环调用对象分配的标签属性并分配额外的内存。
● 使用ObjectPool对象池来管理对象:避免频繁的Instance和Destroy,这两个操作都挺耗性能的。
● 尽量不要在Update()函数中做复杂计算:如若需要,可以隔N帧计算一次。
● 尽量减少函数调用栈:如用x = (x > 0 ? x : -x)代替x = Mathf.Abs(x)。
纹理优化
● 纹理压缩格式:iOS使用PVRTC格式;Android使用ETC格式;Windows使用DXT格式。
● 凡是3D场景,都应该尽可能启用MipMaps。如果硬件MipMaps无法满足效果要求:1、使用自己生成的Mipmaps;2、使用Aniso。
● 如果纹理用于UI或2D场景,禁用MipMaps。
● 通过减色的方式降低纹理大小。
内存优化
● 建议总内存控制在150MB以下;堆内存控制在40MB以下。
● 切换场景时避开内存峰值。当前一个场景还未释放就切换到新场景,这时由于两个场景的内存叠加容易造成内存峰值。可以采用在屏幕中间遮盖一个Loading场景,在旧场景释放完成,并且新场景初始化结束后,再隐藏Loading场景。
● 使用Prefabs(凡是场景物体,都应该制作成Prefabs)。
● 通过ObjectPool对象池来避免内存的频繁操作,从而避免内存碎片影响到大内存块的申请;尝试在切换场景时不释放公共UI资源。
● 通过LoadManager,保证在同一时间段内仅载入一个WWW对象,实现顺序加载。
● 纹理内存占用过大:峰值 < 50MB。
● 内存泄露:内存需保持升降一致,避免泄露。
● 网格资源内存过大:峰值 < 20MB。
● 动画片段:内存 < 15MB,警惕资源泄露。
● 音频资源:内存 < 15MB,警惕资源泄露。
渲染优化
● DrawCall数量:峰值 < 250,主体范围(5% - 95%)应在(0 - 200)个之内。
● Triangle数量:峰值 < 100000/帧。
● VBO上传量:峰值 < 5MB,频繁加载的资源使用缓存池缓存。
● Skinned Mesh数量:峰值 < 50,对应Profiler中的MeshSdinning.Update、Animator.Update。
● RenderTexture:数量 < 10。
CPU优化
● Rigidbody数量:峰值 < 50/帧,对应Profiler中的Physics.Simulate。
● 碰撞体数量:峰值 < 100/帧,对应Profiler中的Physics.Simulate。
合理使用AssetBundles
● 采用依赖性打包
● Assetdatabase.GetDependencies
● Push / Pop
● WWW vs. CreateFromFile
● WWW常被用于加载采用Unity标准压缩方法压缩过的AssetBundles。
● CreateFromFile只能加载非压缩格式的本地AssetBundles;可以先采用其他压缩格式进行压缩,下载到本地后自行解压,再行加载和使用。
● AssetBundle.mainAsset的功能往往被忽视
● 它可以是标准的资源asset,用来存储AssetBundles中最重要的资源文件。
● 也可以是TextAsset,其中可以包含任意内容,推荐用来记录每个AssetBundle中的物体列表和信息描述。
Build AssetBundles
● 问题:当修改AssetBundles中的内容时,需要重新Build这些AssetBundles才能使其生效。这个过程往往非常耗时并影响开发效率。
● 开发阶段和发布阶段使用不同的策略:
● 为了提高在Unity Editor中反复修改AssetBundles的调试效率,推荐开发时使用Resources.LoadAssetAtPath来避免重新建立AssetBundles。
● 在发布时才使用唯一的脚本打包AssetBundles。
LoadAssetFromAssetBundle
AssetDatabase.ImportAsset
● AssetDatabase.ImportAsset有三个重要事实:
● 它是将一个外部asset转化为Unity内部能够识别的internal asset,但并不实际在内存中加载asset,更没有返回值。
● 它会根据AssetImporter中的相关设定对asset的相关属性进行修改,尽管两个API之间没有任何的参数传递。
● 它常常被用于在调用BuildPipeline.BuildAssetBundle前强行重新导入一个asset。
● 几种常用的AssetImporter类型:TextureImporter、ModelImporter及MovieImporter。
预处理和后处理函数
● AssetPostprocessor的作用
● AssetPostprocessor可以在import每个asset之前和之后分别自动触发AssetPostprocessor.OnPreprocessXXX和AssetPostprocessor.OnPostprocessXXX。
● 方便用户介入和修改资源导入的过程。
Build Player
● 自动编译Player
● 支持命令行进行编译。
● 编写编译脚本,并放在Assets/Editor目录下。
● 脚本中声明一个类,包含一个静态方法,通过BuildPipeline.BuildPlayer来实现编译工作。
● 编译后处理脚本
● Unity支持在编译好可执行程序之后,通过后处理脚本对其进行一定的修改,例如制作安装文件等。
● 在Windows平台下,可以在编辑器脚本(Editor Script)中使用BuildPipeline.BuildPlayer方法来进行编译,并在其后添加任意的后处理代码。
● 在Mac平台下,Unity在编译工程后会自动查找一个名为PostprocessBuildPlayer的后处理脚本文件,用于实现编译后处理;后处理脚本可以是sh、perl或任意与命令行兼容的语言。
项目发布策略
● 对移动芯片的支持
● 从Unity 4.0开始,Unity停止了对ARM V6架构的支持。
● Unity 3.5.x版本仍旧支持ARM V6架构。
● Graphics Emulation
● 在不使用实际硬件设备的前提下,在Unity编辑器中就可以模拟测试不同图形硬件对当前项目中所使用的图形API的支持能力(对Editor->Graphics Emulation进行设置)。
● 发布包的代码保护
● Unity脚本在iOS平台下是安全的,与是否使用AssetBundle无关。
● 对于Android和其他平台,可以采用AssetBundle + TextAsset的方式进行,也可以采用代码混淆的方式进行。
● 在所有平台下都可以使用Native DLL。
● 发布包的代码加密
● 需通过AssetBundle和TextAsset来实现,即把代码编译为TextAsset,并打包入AssetBundle中,参考官方文档:“Including scripts in AssetBundles”一节:http://docs.unity3d.com/Documentation/Manual/scriptsinassetbundles.html
● 其中TextAsset并不是真正意义上的Text,而是编译好的dll文件,是以binary形式存在的。参考官方文档“Text Asset”中的“Binary data”一节:http://docs.unity3d.com/Documentation/Components/class-TextAsset.html
● 发布包的美术资源加密
● 对于所有平台,最常见的是对贴图进行加密,通过AssetBundle和TextAsset来实现。
● 程序发布后的增量更新
● 原理:Unity脚本经过编译后就不能再修改,但是可以添加。
● 方案1:将脚本与资源全部分离。
● 项目管理非常麻烦。
● 动态挂载所有脚本。
● 无法在编辑器中使用动态编辑。
● 方案2:将接口与实现分离。
● 不改变用户工作流程。
● 仍可在编辑器重使用动态编辑。
● 对代码起到一定的保护作用(可以混淆)。
● 对原有的AssetBundles打包方案没有任何影响。
unity3d代码优化标准的更多相关文章
- 【译】Unity3D Shader 新手教程(2/6) —— 积雪Shader
本文为翻译,附上原文链接. 转载请注明出处--polobymulberry-博客园. 如果你是一个shader编程的新手,并且你想学到下面这些酷炫的技术,我觉得你可以看看这篇教程: 实现一个积雪效果的 ...
- 跟Unity3D学代码优化
今天我们来聊聊如何跟Unity学代码优化,准确地说,是通过学习Unity的IL2CPP技术的优化策略,应用到我们的日常逻辑开发中. 做过Unity开发的同学想必对IL2CPP都很清楚,简单地说,IL2 ...
- Unity3D 移动开发代码优化
1. 尽量避免每帧处理 比方: function Update() { DoSomeThing(); } 可改为每5帧处理一次: function Update() { if(Time.frameCo ...
- Unity3D 5.3 新版AssetBundle使用方案及策略
1.概览 Unity3D 5.0版本之后的AssetBundle机制和之前的4.x版本已经发生了很大的变化,一些曾经常用的流程已经不再使用,甚至一些老的API已经被新的API所取代. 因此,本文的主要 ...
- 从Unity3D编译器升级聊起Mono
接前篇Unity 5.3.5p8 C#编译器升级,本文侧重了解一些Mono的知识. Unity3D的编译器升级 新升级的Mono C#编译器(对应Mono 4.4) Unity编辑器及播放器所使用的M ...
- Thinking in Unity3D:渲染管线中的Rendering Path
关于<Thinking in Unity3D> 笔者在研究和使用Unity3D的过程中,获得了一些Unity3D方面的信息,同时也感叹Unity3D设计之精妙.不得不说,笔者最近几年的 ...
- Unity3D脚本行尾(Line Endings)
行尾不一致(inconsistent line endings ) 开发环境 有时候编辑Unity的脚本文件,代码diff之后,或者从svn更新文件之后,Unity中会出现行尾不一致的信息. 我的开发 ...
- Unity3D的四种坐标系
[Unity3D的四种坐标系] 1.World Space(世界坐标):我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在场景中的.transform.position可以获得该位置坐标. ...
- 关于Unity3D手机网游开发一些小看法
它的知识技能和职责,我就不仔细说了,说细了有一点像招聘启示.他的主要职责虽然负责技术,但是也给产品决策和方向提供一些决策.他最主要的考核指标,就是经验很重要,最好主导或参与过一款网络游戏的开发.举个例 ...
随机推荐
- c++重载operator的示例 非原创
#include<iostream> #include<vector> using namespace std; class test{ public: int v; /*构造 ...
- [转] vagrant系列(2):使用Vagrantfile实现集成预安装
在我们的开发目录下,有一个文件Vagrantfile,里面包含有大量的配置信息,主要包括三个方面:虚拟机配置.SSH配置.基础配置.Vagrant是使用Ruby开发的,所以它的配置语法也是Ruby的, ...
- Oracle 创建数据库卡死在85%
Oracle 创建数据库卡死在85%处理方法 1.首先用改工具,删除数据库 2.对应的目录 3.重启服务器(本次尝试有重启,在有其他数据库在跑的情况下,可以试试不重启)
- 使用swiper来实现轮播图
使用swiper来实现轮播图 swiper实现轮播图几乎是没有一点点技术含量,但是用起来却很方便,包括对移动端的支持也很好. 由于简单这里当然就不会去详细介绍了,推荐两个网址: 1.http://ww ...
- MATLAB拟合和插值
定义 插值和拟合: 曲线拟合是指您拥有散点数据集并找到最适合数据一般形状的线(或曲线). 插值是指您有两个数据点并想知道两者之间的值是什么.中间的一半是他们的平均值,但如果你只想知道两者之间的四分之一 ...
- c++ 网络编程(三) LINUX/windows 进程间的通信原理与实现代码 基于多进程的服务端实现
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9613027.html 锲子:进程与线程是什么,他们的区别在哪里: 1 进程概念 进程是程序的一 ...
- leetcode简单题目两道(1)
Problem: You are playing the following Nim Game with your friend: There is a heap of stones on the t ...
- 《c++primer》疑惑记录
第4章 96页,数组维数为变量 第8章 246. IO对象不可复制.赋值原因是类设计时复制构造函数.赋值函数是私有的,为什么这么设计呢? 251. tie举例 第15章 484 派生类可以恢复,但不可 ...
- Getting over the dangers of rm command in Linux---reference
reference:http://www.coolcoder.in/2014/01/getting-over-dangers-of-rm-command-in.html When we want to ...
- 持续集成:TeamCity 的安装和使用
TeamCity 本文初衷 让大家了解持续集成(CI),以及入门了解 JetBrains 家的 TeamCity 的一些简单实用. TeamCity 的一些复杂使用我暂时也不会,一样也是要看文档的,所 ...