Unity GC 优化 贴士大全

作者:吴小含

导语 :Unity中频繁的垃圾回收往往是造成手游性能瓶颈的一大元凶,本文对常见的造成频繁垃圾回收的原因做一个扫描,让开发者在日常开发中可以有意识的避开这些问题。

  1. Struct 会分配在栈上,但是 Struct[] 会分配在堆里。
  2. GetType() 方法会产生 GC Alloc ,每次调用会产生 20 Bytes 的大小。
  3. Delegate 在赋值操作时,等同于一次 new Delegate。
  4. Delegate 在进行+=操作时,如果原本Delegate是 Simple Delegate则会有一次转换,并更新InvocationList。
  5. 由于Unity的GC是采用 Boehm GC 原理, 对象数量 > 引用关系复杂度 > 对象尺寸这一优化原则可以作为通用的优化原则。
  6. 利用数组对于GC是一个对象的原则,可以对原本储存在List中的对象进行一些属性分离来优化GC。

比如有100个对象存在一个List里,那GC的次数就是101次(List本身占一次)

class Foo
{
    int a;
    float b;
    bool c;
    string str;
}

但是如果将它们的属性进行拆分,将所有值属性放到一个struct里,如:

struct Foo_S
{
    int a;
    float b;
    bool c;
}

Foo_S[] fooArray;
string[] strArray;

那这100个对象的GC次数就会降低为2次

  1. 单个的值属性 ValueType 分配是在栈上进行,但是ValueType[] 永远是在堆上。
  2. 避免在代码中频繁调用会分配内存的 accessors (如 .vertices/.normals/.uvs/.bones)。
  3. 避免频繁调用 Int.ToString() 及其它类型的衍生。
  4. 避免在 Update() 内使用 GameObject.Tag 和 GameObject.Name。
  5. 避免在 Update() 内 GetComponent() 和 GetComponentInChildren()。
  6. 避免在 Update() 内访问 animation 组件。
  7. 避免在 Update() 内 FindObjectsOfType()。
  8. 避免在 Update() 里赋值给栈上的数组,会触发堆内的反复分配。
  9. 避免频繁使用 Mathf.Max 等函数的数组版,重载中的多参数都会调到数组版。
  10. 避免频繁使用参数中带 params 修饰的函数。
  11. 在不需要时避免使用 GUILayout - OnGUI 时把 useGUILayout 关掉
  12. 避免使用 foreach,可以先拿到迭代器,然后进行迭代。
  13. 避免使用枚举或 struct 做 Key 进行字典查找,由于C# 在Dictionary 的主要接口 Add / ContainsKey / TryGetValue 在被调用时都需要对传进来的 TKey 调用默认的 EqualityComparer 来判断是否相等
this.comparer = comparer ?? EqualityComparer<TKey>.Default;

而 EqualityComparer 的内部有私有方法 CreateComparer() 来创建真实的 Comparer,内建类型(int/float 等等)已经实现了良好的 Equality 判断,而用户定义的 struct 则没有,每次调用 Add / ContainsKey / TryGetValue 等接口时,EqualityComparer 会为你创建一个Comparer。

要避免这一问题,可以人为指定对象的Comparer 或者对你的自建struct实现Equals() 和 GetHashCode() 等方法。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JMCui

Swagger文档转Word 文档

GitHub 地址:https://github.com/JMCuixy/SwaggerToWord/tree/developer 一、前言     为什么会产...

4698
来自专栏技术博客

菜菜从零学习WCF十(序列化)

 本次课程的主要内容包括以下四格部分:DataContractSerializer、序列化、反序列化、XmlSerializer

733
来自专栏Java帮帮-微信公众号-技术文章全总结

Java面试系列16-jdbc、hibernate、流、线程实现、多态、继承事程序执行顺序等

1 JDBC,Hibernate 分页怎样实现? 方法分别为: 1) Hibernate 的分页: Query query = session.createQ...

2733
来自专栏腾讯Bugly的专栏

如何定位Obj-C野指针随机Crash(三):如何让Crash自报家门

本文主要介绍如何利用OC Runtime的特性,让OC野指针对象主动抛出自己的信息,秒杀某些全系统栈Crash。 ? 陈其锋,腾讯SNG即通产品部音视频技术中心...

4233
来自专栏JackieZheng

Hadoop阅读笔记(六)——洞悉Hadoop序列化机制Writable

  酒,是个好东西,前提要适量。今天参加了公司的年会,主题就是吃、喝、吹,除了那些天生话唠外,大部分人需要加点酒来作催化剂,让一个平时沉默寡言的码农也能成为一个...

1965
来自专栏salesforce零基础学习

salesforce 零基础开发入门学习(十一)sObject及Schema深入

sObject在salesforce中占有举足轻重的位置,除了在数据库中数据以外,我们还应该关心一下他的元信息。元信息封装在Schema命名空间内。 作为面向对...

1856
来自专栏程序员的SOD蜜

使用操作符重载,生成ORM实体类的SQL条件语句

ORM框架的一个不可或缺的功能就是根据实体类,生成操作数据库的SQL语句,这其中,最难处理的就是那些复杂的SQL条件比较语句。比如,有下面这样一个SQL语句: ...

21510
来自专栏MasiMaro 的技术博文

windows 异常处理

为了程序的健壮性,windows 中提供了异常处理机制,称为结构化异常,异常一般分为硬件异常和软件异常,硬件异常一般是指在执行机器指令时发生的异常,比如试图向一...

1212
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(7)-MVC与EasyUI DataGrid

本节知识点 为了符合后面更新后的重构系统,文章于2016-11-1日重写 EasyUI读取MVC后台Json数据 开始实现 我们的系统似乎越来越有趣了 首先...

3056
来自专栏IMWeb前端团队

Redux源码解析系列(四)-- combineReducers

本文作者:IMWeb 黄qiong 原文出处:IMWeb社区 未经同意,禁止转载 combindeReducer 字面意思就是用来合并reducer的...

1787

扫码关注云+社区