Unity Cpu优化大全
来源:互联网 发布:电商数据分析软件 编辑:程序博客网 时间:2024/05/16 04:36
原文链接
前言
观察AppStore中游戏应用的评论,玩家对手机发热这一项评论的非常多。在玩家眼里这是游戏优化的不够好,太耗电。主要原因是CPU运算量大。这篇文章从两个方面介绍如何提高运算效率。其中“使用技巧”主要介绍在Unity研发中一些使用不当的方式,以及如何修正。“算法优化”项算是抛砖引玉,算法的优化总是无止境的,不同项目类型都有自己需求。
使用技巧
神奇的启动时间
在刚开发Unity项目时,遇到了一个非常棘手的问题。游戏启动时内存占用非常高(90M)。我使用二分法,排查是哪里分配的内存。但是结果令我非常的不解,因为当我用二分法,一直排除到程序启动至加载一个场景,一行代码都不执行,但App启动后内存占用缺还是很高(85M)。为了排除场景有未排除的代码, 新建了空白scene。 在google上搜索了好久关于启动内存高的问题,都没有得到答案。此刻只好怀疑到资源这块,通过删除Resources下的资源,神奇的事情发生了,启动内存降低了,自然启动速度就非常快。
直到看Unite 2006的开发者大会性能优化演讲,才看到Unity会根据Resources目录下的资源生产对应的Entity信息,在App启动时会加载所有的资源信息,资源越多,对应需要的内存越多,时间越久。这么重要的信息Unity官方尽然没有任何说明,这令我非常惊奇。
我这边的项目解决办法就是使用AssetBundle,Resources目录下放少量的资源,解决了问题。官方在Unite 2016大会上也是给出的相同的方案,希望能帮到大家。
延迟解析
在项目设计过程中,我们经常将加载解析配置当做完整的模块,将所有配置文件加载并解析。由于许多模块都依赖配置文件,一般将配置文件启动时加载,当项目大的时候,会发现这里非常拖慢启动速度。这里将配置文件分为以下几类:
- 提前加载配置文件,启动时加载
- 尤其运行必须的配置文件,比如版本号,远端服务器地址
- 影响游戏启动后显示的配置,因为加载文件有卡顿的情况,所以放在loading时加载是值得的
- 所需及所求的文件,当使用时加载,解析,缓存
数组遍历
数组的遍历非常常见,尤其在使用Unity Api是更加需要注意,Unity Api 返回数组每次都会返回新的数组,如果每次都访问数据,不仅分配了不必要的内存,还增加cpu调用次数。
1
2
3
4
5
6
7
8
9
10
11
12
13
// bad
// 这里调用了 n的2次方 Input.touches ,n = Input.touches.Length;
for
(
int
i = 0; i < Input.touches.Length; ++i)
{
Touch touch = Input.touches[i];
}
// good
// 这里只调用了 1次 Input.touches
Touch[] touchArr = Input.touches;
int
len = touchArr.Length;
for
(
int
i = 0; i < len; ++i)
{
Touch touch = touchArr[i];
}
内联函数
C#并没有C++的内联函数,在类内部使用时使用成员变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public
class
Player
{
private
int
m_playerId;
public
int
playerId
{
get
{
return
m_playerId; }
set
{ m_playerId = value; }
}
private
void
Update(
int
id)
{
// bad
playerId = id;
// 这里会调用 get 函数
// good
m_playerId = id;
// 直接访问成员变量
}
}
1
2
3
4
5
6
7
8
9
10
private
Transform m_transform;
void
Start()
{
m_transform = transform;
}
void
Update()
{
m_transform.Translate(
new
Vector3(1, 1, 0), Space.World);
// 大量调用时,减少调用链
}
SendMessage()
此函数是用来向特定对象发送消息函数,由于会遍历对象所有节点,效率不高。通过监听者模式,效率更高。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static
class
MessageMgr
{
public
static
void
RegisterMsg(
string
msgType, System.Action callBack)
{
}
public
static
void
DispatchMsg(
string
msgType)
{
}
}
void
SendMsgToPlayer()
{
// bad
SendMessage(
"InitPlayer"
,
this
);
// 会遍历整个Object的子节点,判断是否有InitPlayer方法
MessageMgr.DispatchMsg(
"MsgInitPlayer"
);
// 自定义消息管理, 定向发送消息,效率更高
}
反射
反射在编译到IOS平台时,并没有明确说明转换过程,使用时需要测试方可放心使用,下面说说遇到一个问题。
1
2
3
// 这里会在ios上分配内存,如果非要使用,并且调用次数很多,做缓存
System.Type t = System.Type.GetType(
"Player"
);
Player p = (Player)System.Activator.CreateInstance(t);
p.playerId = 10001;
携程
携程有效的分摊cpu 最大峰值。下面的例子介绍,如何分段加载游戏场景。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void
LoadLevel()
{
int
level = 2;
StartCoroutine(LoadLevelCoroutine(level));
}
IEnumerator LoadLevelCoroutine(
int
level)
{
// load secene
yield
return
new
WaitForEndOfFrame();
// load ui
yield
return
new
WaitForEndOfFrame();
// load audio
yield
return
new
WaitForEndOfFrame();
// load actor
yield
return
new
WaitForSeconds(1.0f);
}
第三方库
使用效率高的库,在使用第三方库的时候,多做比较分析,得出最优的效率库。
1
2
3
4
PlayerInfo litPlayerInfo = JsonMapper.ToObject(litJsonStr);
// LitJson
PlayerInfo unityJsonInfo = JsonUtility.FromJson(litJsonStr);
// Unity 自带的JsonUtility 效率差很多倍
缓存
多使用缓存, 不要重复计算,下面的例子,一个是每次在使用数据时解析json,另一个是解析好后,每次调用直接使用缓存。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[System.Serializable]
class
PlayerConfig
{
public
int
id;
public
string
name;
}
private
PlayerConfig m_config;
private
string
m_jsonStr;
private
PlayerConfig ParseConfig(
string
jsonStr)
{
return
JsonUtility.FromJson(jsonStr);
}
private
void
InitConfig()
{
m_jsonStr =
"{\"id\":1001, \"name\":\"lfwu\"}"
;
m_config = ParseConfig(m_jsonStr);
}
private
void
Update()
{
// bad
int
id = ParseConfig(m_jsonStr).id;
// good
id = m_config.id;
}
字符串
字符串比较时,.net 涉及到语言相关项,会拖累速度,建议使用string.Equals,Compare的速度很慢, 因此在使用 string.IndexOf(), string.LastIndexOf() 需要注意语言相关问题。
1
2
3
4
5
6
7
8
9
10
11
12
string
str1 =
"hello, world"
;
string
str2 =
"hell0, wor1d"
;
// bad
int
ret = 0;
ret =
string
.Compare(str1, str2);
// 语言相关,速度慢
ret = str1.CompareTo(str2);
// 语言相关,速度慢
// good
bool
isSame =
false
;
isSame = str1.Equals(str2);
isSame = str1.Equals(str2, System.StringComparison.Ordinal);
// 速度快,按字符2进制比较
Dictionary
使用ContainsKey判断,在调用取值,调用了两次取值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Dictionary<
int
,
string
=
""
> playerDic =
new
Dictionary<
int
,
string
=
""
>
{
{ 10001,
"lfwu"
},
{ 10002,
"xiaoy"
}
};
int
id = 10001;
if
(playerDic.ContainsKey(id))
{
return
playerDic[id];
}
else
{
return
string
.Empty;
}
1
2
3
4
5
6
7
8
9
10
11
Dictionary<
int
,
string
=
""
> playerDic =
new
Dictionary<
int
,
string
=
""
>
{
{ 10001,
"lfwu"
},
{ 10002,
"xiaoy"
}
};
int
id = 10001;
string
ret =
string
.Empty;
playerDic.TryGetValue(id,
out
ret);
return
ret;
内置函数
在创建脚本继承MonoBehaviour时,删掉默认不用的函数,这些函数都会被调用。
1
2
3
void
Awake() {}
void
Start() {}
void
Update() {}
Update
在戏开发中Update调用非常常见,Unity中类继承MonoBehaviour,会自动注册Update函数。
1
2
3
4
5
6
7
8
9
private
List m_updateList =
new
List();
private
void
Update()
{
int
len = m_updateList.Count;
for
(
int
i = 0; i < len; ++i)
{
m_updateList[i]();
}
}
设置帧率
Unity默认帧率是60,针对不同的游戏可以设置不同的帧率,设置合理的帧率,提高性能,减少cpu调用次数。
1
Application.targetFrameRate = Config.kFrameRate;
算法优化
遇到被除数是2的时候,可以改为乘法运算。
1
2
3
4
5
// bad
float
ret = dis / 2.0f;
// good
float
ret = dis * 0.5f;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Vector3 posA =
new
Vector3(1, 1, 1);
Vector3 posB =
new
Vector3(2, 2, 2);
// bad
float
minDis = 10.0f;
float
dis = Vector3.Magnitude(posA - posB);
// 这里调用了开平方,效率比较低
if
(dis < minDis)
{
}
// good
float
sqrMinDis = 10.0f * 10.0f;
float
sqrDis = Vector3.SqrMagnitude(posA - posB);
// 平方和,速度很快
if
(sqrDis < sqrMinDis)
{
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
float
Q_rsqrt(
float
number )
{
long
i;
float
x2, y;
const
float
threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * (
long
* ) &y;
// evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 );
// what the fuck?
y = * (
float
* ) &i;
y = y * ( threehalfs - ( x2 * y * y ) );
// 1st iteration
return
y;
}
总结
只有对自己对每一行代码的性能消耗胸有成竹,才能做到如庖丁解牛那般轻松。
0 0
- Unity Cpu优化大全
- 【Unity优化】CPU优化
- [Unity 优化]CPU优化
- Unity优化大全(二)之CPU-DrawCall- Batching
- Unity优化大全(三)之CPU-Physics
- Unity优化大全(五)之CPU- VSync Count
- Unity优化大全(二)之CPU-DrawCall- Batching
- Unity优化大全(三)之CPU-Physics
- Unity优化大全(五)之CPU- VSync Count
- Unity优化大全(一)之CPU-DrawCall- Batching
- Unity优化大全(二)之CPU-Physics
- Unity优化大全(四)之CPU- VSync Count
- 【Unity】CPU优化
- 【unity优化三】CPU
- Unity CPU 优化
- [Unity优化] Unity CPU性能优化
- unity 优化大全
- Unity性能优化(CPU)
- 初识Linux系统命令
- php接口
- 初步学习SpringMVC
- Hyper-V学习笔记
- 获取元素,获取节点详解
- Unity Cpu优化大全
- js的splice() 函数
- 王朝 第十一周 等比数列
- 【转载】SAP中AUTHORITY-CHECK 的使用
- 【框架-MFC】关于CFileDialog保存文件获取扩展名(后缀名)
- DB主从一致性架构优化4种方法
- csv文件在BSP调试中的一个运用
- 【NOIP2016提高组11.7】涂色游戏
- 关联域名挖掘