Unity C# 游戏客户端面试复习

本文是针对Unity C#游戏客户端面试的复习资料,涵盖了C#的装箱与拆箱、垃圾回收机制、面向对象特性、游戏引擎组成、设计模式、资源管理、数据结构等内容。深入探讨了C#中的多态实现、接口与抽象类、堆栈内存管理,以及游戏开发中的关键概念,如LOD、Shader、动画模式等。此外,还涉及了各种设计模式和内存管理策略,如单例模式、委托、排序算法和堆、栈内存的区别。
摘要由CSDN通过智能技术生成

Unity C# 游戏客户端面试复习

为了游戏客户端而自己准备的面试复习资料,若有错误欢迎指正

C# 装箱与拆箱操作

装箱:值类型=>引用类型
拆箱:引用类型=>值类型

  • .Net中,数据类型划分为值类型与引用类型,由此内存分配划分为两种方式:
  • 栈(值类型一般在栈中分配,但并不是所有值类型都在栈中)
  • 堆(引用类型在堆中分配,托管堆用于垃圾回收GC)
  • 装箱过程使用的是值类型的一个副本,因此对原有值类型的改变不会影响装箱后的对象,拆箱过程会拷贝值类型,同样原有引用类型的改变不会影响拆箱后的值类型

装箱步骤

  • 首先从托管堆中为新生成的引用对象分配内存(大小为值类型实例大小加上一个方法表指针和一个SyncBlockIndex),然后将值类型的数据拷贝到刚刚分配的内存中
  • 返回托管堆中新分配的对象地址,其中指向对象的引用其中分配内存与拷贝数据均比较花费时间

拆箱步骤

  • 首先获取托管堆中属于值类型部分字段的地址,进行严格意义上的拆箱
  • 将引用对象中的值拷贝到位于线程堆栈上的值类型实例中
  • 严格意义上的拆箱不影响性能,但是随后的数据拷贝过程会影响性能

装箱、拆箱的使用场景

  1. 一个含类型为Object的参数的方法,该Object可支持任意为型,以便通用。当你需要将一个值类型(如Int32)传入时,需要装箱。
  2. 非泛型的容器,同样是为了保证通用,而将元素类型定义为Object。于是,要将值类型数据加入容器时,需要装箱。
  3. 字符串转成值类型的时候会出现拆箱(很普遍)

装箱/拆箱 避免方法:使用重载函数或是泛型来避免

C# 垃圾回收主动触发模式

Unity的自动内存管理

  • Unity 可以访问两个内存池:栈(stack)和堆(heap)(also known as the managed heap)。栈用于短期存储的小数据,堆用于较长时间存储的较大的数据块。
  • 当创建变量的时候,Unity 会从栈或堆中请求一个内存块。
  • 只要变量值作用域内(in scope(仍可被代码访问) ),分配给它的内存仍然会保留。我们说的内存被分配( allocated )了。我们可以这样描述,保存在栈内存的叫做栈对象(object on the stack),保存在堆内存的叫做堆对象(object on the heap)。
  • 当变量不在作用域范围内了,这块内存就不再需要了,可以被创建它的那个内存池回收。当内存被回收到池,我们说内存被重新分配(deallocated)了。只要变量的引用超出了作用域,栈内存就会被重新分配,而堆的内存不同,这种情况下内存不会重新分配即使变量的引用超出了作用域。
  • 垃圾回收器标识和回收没有使用的堆内存。垃圾回收器定期清理堆内存。

栈内存:

  • 栈工作类似栈数据类型:这种情况下的内存更像一个简单的集合,元素按严格的顺序添加和移除。这种简单性和严格性使它如此快速:当变量存储在栈时,它的内存只从栈顶分配。当一个栈变量离开作用域,存储变量的内存会立即被栈重用。
  • 堆内存:堆分配内存比栈分配内存要复杂得多。这是因为,堆可以用来存储长期数据和短期数据和不同类型和大小的数据。分配和释放不总是按可预见的顺序,并且可能需要非常不同大小的内存块。当创建一个堆变量的时候,会按以下的步骤:
    • 首先,Unity 会检查堆是否有足够的剩余内存。如果堆有足够的剩余内存,就会为变量分配内存。
    • 如果堆内有足够的剩余内存,Unity 触发垃圾回收尝试释放不使用的堆内存。这可能是一个很慢的操作。如果这时堆有足够的剩余内存,则会为变量分配内存。
    • 如果垃圾回收后,堆剩余内存仍然不够,Unity 会在堆中增加内存。这可能是一个很慢的操作。然后为变量分配内存。
    • 堆分配可能会很缓慢,尤其是需要运行垃圾回收器或扩展堆内存的时候。
    • 当一个堆变量离开作用域,存储该变量的内存不会被立即释放。不使用的堆内存只有在垃圾回收器运行时候才会释放。
  • 每次垃圾回收器运行,会发生以下的事情:
    • 垃圾回收器检查堆中每个对象
    • 垃圾回收器搜索所有当前对象的引用以确定堆对象是否在作用域。
    • 任何不在作用域的对象都打一个删除的标记。
    • 分配给打了删除标记的对象的内存会被堆回收。
  • 垃圾回收什么时候发生?
    • 请求堆内存分配的时候,剩余内存不能满足时,垃圾回收器会运行。
    • 垃圾回收器不时的自动运行(不同的平台频率不同)。
    • 垃圾回收可以手动运行gc接口。
  • 垃圾回收可能是一个频繁的操作。请求对内存分配,内存不足时候会触发垃圾回收器,这意味频繁的堆内存申请和释放可能导致频繁的垃圾回收。

减少垃圾回收的几种方法:

  • 使用缓存,避免在频繁调用的函数中申请内存
  • 对象池技术
  • 字符串String是引用类型,容易产生垃圾
  • 减少装箱/拆箱操作

堆栈内存的黄金规则

  • 引用类型永远存储在堆里
  • 值类型和指针类型永远存储在他们声明时所在的堆或栈中:如果一个值类型不是在方法中定义的,而是在一个引用类型里,那么此值类型将会被放在这个引用类型里并存储在堆上。
  • 结构体struct是值类型,需要小心地去使用它,因此对于这种情况,考虑使用ref关键字,只是去传递原始值类型的引用。
  • 此部分内容参考

面向对象(多态与虚函数表)

面向对象的三个特征:封装,继承与多态

  • 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。
    • 重载(overload): 在同一个作用域(一般指一个类)的两个或多个方法函数名相同,参数列表不同的方法叫做重载,它们有三个特点(俗称两必须一可以):
      • 方法名必须相同
      • 参数列表必须不相同
      • 返回值类型可以不相同
    • 重写(override):子类中为满足自己的需要来重复定义某个方法的不同实现,需要用 override 关键字,被重写的方法必须是虚方法,用的是 virtual 关键字。它的特点是(三个相同):
      • 相同的方法名
      • 相同的参数列表
      • 相同的返回值。
    • 虚方法:即为基类中定义的允许在派生类中重写的方法,使用virtual关键字定义。等同于C++中的虚函数。
    • 抽象方法:在基类中定义的并且必须在派生类中重写的方法,使用 abstract 关键字定义。
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值