zoukankan      html  css  js  c++  java
  • Unity知识

    Monobehaviour生命周期

    一图流

    碰撞体和触发器的区别

    使用条件的区别

    • 触发器使用时需要在碰撞体上勾选isTrigger,勾了之后将不会产生碰撞效果,碰撞体和触发器两者不能共存
    • 触发器的主动方需要携带RigidBody和碰撞体,被动方只需要携带一个触发器即可;或主动方携带RigidBody和触发器,被动方携带碰撞体
    • 碰撞体则需要主动方携带RigidBody,两者都需要有碰撞体

    用途的区别

    碰撞体能够模拟真实的物理碰撞;而触发器更适合做一个触发功能:比如主角走到了保存点,主角接触到地面的物品自动捡起

    Unity中的GC

    Unity中使用C#进行编程,内存部分分为栈区和堆区。

    其中栈区的内存由操作系统负责分配和回收,堆区的内存需要手动申请和通过GC机制来回收。

    堆区申请和回收的速度都比栈区要慢。在GC时,需要扫描整个堆区的内存,然后找出其中被标记为可回收的,最后执行回收操作

    什么会导致GC

    • 手动调用GC
    • 系统会按照一定的频率自动GC
    • 当申请堆空间但是当前空间不足的时候

    申请堆空间后可能发生的事情是什么

    • 内存空间足够,正常申请
    • 内存空间不够,正常申请后失败,然后进行GC,最后成功申请
    • 内存空间非常缺乏,进行GC后仍然失败,需要扩充堆空间

    GC是比较耗时的,扩充堆空间也耗时,所以如果不注意优化的话,GC频繁,游戏性能下降

    GC的步骤是什么

    • 首先会扫描所有堆上的对象
    • 然后根据对象的引用数量判断是否可以删除
    • 标记可以删除的对象
    • 删除标记的对象

    也就是说,堆上的对象越多,GC的开销越大

    GC频繁的害处是什么

    首先频繁的GC代表多次的内存申请和回收,它和先进后出的栈不同,频繁的GC可能会导致内存碎片的产生,从而导致更频繁的GC

    进行GC的时候最直接的表现就是掉帧

    如何减少GC

    把GC放在不为人知的地方

    比方说可以在游戏的设置界面或者在加载界面手动进行GC,这样用户不易察觉到

    减少GC

    • 最基本的,装箱拆箱操作就会导致产生更多的内存垃圾,导致GC的发生,所以应该尽量避免装箱拆箱

    • string类型是引用类型,也就是说需要在堆上分配空间,那么使用频繁的使用+号进行字符串拼接,肯定会导致垃圾的产生。所以应该尽量使用StringBuilder来完成这易操作

    • 不要频繁的在Update函数中申请堆空间

    • 协程也会产生内存垃圾,因为Unity会创建一个实体来管理协程

      // 携程中使用不当也会导致GC
      // 装箱操作
      yield return 0;
      
      // 每次调用都构建了一个新的堆区对象
      yield return new WaitForSecond(1f);
      
    • LinQ表达式采用装箱方式实现,也会造成GC

    一图流

    协程与多线程

    Unity中的性能优化

    脚本方面

    • GetComponentInstantiateSetActive,IO操作等耗时较长的接口应该在Loading的时候做
    • 用移除屏幕代替UI的SetActive(false)。因为SetActive会去遍历当前物体及它的所有子物体,然后执行对应的OnEnableOnDisable操作
    • 减少使用==号对gameObject的使用
    • 子物体过多的Gameobject应该减少对其进行Transform变换
    • 使用StringBuilder代替string,减少gc
    • 减少临时对象的创建,减少gc
    • 减少装箱拆箱的操作,使用装箱拆箱操作的容器有:ArrayListHashtable
    • 在不影响游戏体验的时候(例如Loading、设置界面)主动通过System.GC.Collect()调用垃圾回收

    图像方面

    降低DrawCall

    • 批处理:将使用相同渲染状态的网格合并,一次性交给GPU进行渲染

      静态批处理:适用于场景中不会运动的物体,材质相同的物体会被合并在一起

      动态批处理:由Unity自动完成。我们做的工作就是辅助Unity自动合并更多的物体:在shader中减少使用顶点属性,或尽量减少模型的顶点数量

    • GPU Instancing:将同一材质,同一网格的物体合并,一次性交给GPU进行渲染。

      使用了不同的颜色或者贴图的(uniform)都不属于同一材质;物体缩放不会影响Instancing

    Unity中快速移动物体穿墙

    https://www.zhihu.com/question/39177106

    C#装箱拆箱

    装箱拆箱是什么

    理解层面来讲:值类型转换为引用类型叫做装箱;引用类型转化为值类型叫做拆箱

    装箱拆箱的坏处

    首先装箱和“拆箱”带来的内存分配和数据拷贝是耗时的,而且传参时产生的装箱拆箱会产生内存垃圾,导致内存占用,从而导致GC的发生

    什么会导致装箱拆箱

    使用非泛型的容器可能会,例如ArrayList和HashTable

    LinQ表达式也是使用装箱实现的,所以也可能会

    装箱拆箱执行了什么

    从定义层面来讲:

    • 装箱
      • 首先需要在堆中分配内存(大小为值类型实例大小加上一个方法表指针和一个SyncBlockIndex)
      • 然后将栈中的数据拷贝至堆
      • 最后返回一个引用指向该内存空间
    • 拆箱
      • 获取到箱子中属于值类型字段的那个地址
      • (将该地址中的数据拷贝到栈中的值类型中)——这一步其实不属于拆箱,但是是”拆箱“的必经之路

    如何改变箱子中物体的值

    public struct A
    {
        public int data;
        public void Change(int num) { data = num; }
    }
    
    public interface IChange
    {
        void Change();
    }
    public struct B : IChange
    {
        public int data;
        public void Change(int num) { data = num; }
    }
    
    // 尽管有new但是还是分配在栈上 不要被C++误导
    A a = new A();
    object o = a;
    ((A)o).Change(300);
    // 结果还是0 无法修改a中的数据 因为这是拆箱之后产生的一份拷贝
    Debug.Log(((A)o).data);
    
    B b = new B();
    object o = b;
    ((IChange)o).Change(100);
    // 成功修改
    Debug.Log(((B)o).data);
    
    public class C
    {
        public int data;
        public void Change(int num) { data = num; }
    }
    
    C c = new C();
    // 不存在装箱的操作 只是单纯的类型转换
    object o = c;
    ((C)o).Change(500);
    // 成功修改
    Debug.Log(((C)o).data);
    

    C#中的struct和class

    • struct是值类型,按值传递,内存分配在栈上;class是引用类型,按引用传递,内存分配在堆中
    • struct不能有无参构造函数和析构函数,只能继承接口。调用struct中的有参构造函数需要使用到new
    • struct创建时可以不适用new,但是要需要对它的成员(全部)进行赋值,然后才能使用。class的对象创建时必须使用new后才能使用
    • struct中若包含了引用类型,那么该引用类型还是存放在堆上的。class中如果包含了值类型,那么值类型是存放在堆上的
    • struct中默认的修饰符是public但是class中是private
    • struct中不能使用abstract,virtual和protected修饰符
  • 相关阅读:
    mvc 4 ActionFilterAttribute 特性,进行权限验证
    asp.net 将word文档进行编辑并导出一个新的word
    怎样才能最快速的找到破解软件?
    C#动态执行字符串(动态创建代码)
    使用Memcached提高.NET应用程序的性能
    ASP.NET 创建网站地图
    TFS2010安装办法及序列号
    在将 varchar 值 '1,2,3,4,5,6,7,8' 转换成数据类型 int 时失败。
    Js获取当前日期时间及其它操作
    截取Excel字符串的部分字符
  • 原文地址:https://www.cnblogs.com/tuapu/p/15226394.html
Copyright © 2011-2022 走看看