当前位置: 首页 > article >正文

Unity GC

本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com

简略版本

在 Unity 中,垃圾回收(Garbage Collection,GC)采用的是基于标记-清除(Mark and Sweep)算法的自动内存管理机制。

基于标记-清除算法的垃圾回收包括以下步骤:

标记阶段(Mark): 在这个阶段,垃圾回收器会遍历程序中的对象,从根对象(如全局变量、活动线程的栈和静态变量等)开始,标记所有能够访问到的对象。这些被标记的对象被认为是“活跃”的,而未被标记的对象则被认为是“垃圾”。

清除阶段(Sweep): 在这个阶段,垃圾回收器会遍历整个堆内存,清除未被标记的对象,释放它们所占用的内存空间。这样就完成了垃圾的回收和内存的释放。

Unity 的垃圾回收器会自动管理内存,并在需要时执行垃圾回收。在游戏开发中,开发者通常不需要显式地调用垃圾回收,因为 Unity 的垃圾回收器会自动处理对象的分配和释放,以确保内存的有效使用和释放。

需要注意的是,虽然标记-清除算法是一种常见的垃圾回收算法,但它可能会产生一些性能上的开销,特别是在大型对象图和频繁的内存分配和释放时。因此,在编写 Unity 游戏时,需要注意内存的优化和对象的重复利用,以减少垃圾回收的频率,提高游戏的性能。

详细版本

在 Unity 游戏开发中,GC(垃圾回收)主要是为了自动管理内存,释放那些不再使用的对象所占的内存。当你在 Unity 中创建一个新的对象,如一个新的类、数组、列表或游戏对象,这需要占用部分内存。当这些对象不再被使用,例如从场景中移除、设置为 null、超出其活动范围等,它们就成为了 "垃圾",需要被清理。这个自动清理无用对象的过程就是垃圾回收。

Unity 的 GC 基于.NET 的内存管理和垃圾回收机制,其工作原理可以大致分为以下步骤:

  1. 标记:遍历所有的对象,找出哪些对象被引用,哪些对象没有被引用。具体做法是从根对象(例如全局对象、静态对象、栈上的对象)开始,寻找它们直接或间接引用的对象,被找到的对象被标记为 “活跃”。

  2. 清除:GC 清除那些被标记为 “非活跃” 的对象,也就是没有被任何地方引用的对象,这些对象占用的内存被认为是可以被安全回收的。清除的方式主要是将这部分内存标记为可用。

  3. 压缩:清除结束后,GC 会尝试将内存中的活跃对象压缩到一起,以减少内存碎片。这一步被称为压缩或整理。注意该步骤不是每次 GC 都会执行,因为它比标记和清除更耗时。

    C# 的 GC 是自动进行的,也可以手动调用 GC.Collect() 进行垃圾回收,但只有在需要处理大量未被引用的对象,或者需要马上释放大量内存时才建议这么做,因为 GC.Collect() 对性能的影响很大。

值得注意的是,GC 操作是非常消耗 CPU 资源的,特别是对于实时运行的游戏应用来说,任何 GC 操作都可能导致游戏卡顿。所以在开发游戏时,我们应尽可能避免频繁触发 GC,在 Unity 游戏开发中,可以通过以下方法尽可能避免或减少 GC:

  • 对象池:这是避免 GC 的最重要和最有效的方法。对象池的主要思想是重用对象,而不是创建新的对象并销毁旧的对象。例如,如果游戏中有很多敌人在不断地出现和消失,那么可以使用对象池来管理这些敌人的对象,而避免在每次需要一个新的敌人时都去创建一个新的对象。

  • 减少或避免在频繁调用的函数中创建对象:例如,在 Update、FixedUpdate、LateUpdate 等函数中如果每次都创建新的对象,则很容易引起 GC。

  • 避免使用 “+” 操作符拼接字符串:字符串是不可变的,使用 “+” 操作符拼接字符串会生成一个新的字符串对象,可以使用 System.Text.StringBuilder 来替代。

  • 使用值类型代替引用类型:值类型如 struct 在栈上分配,不会产生垃圾。尽可能地使用值类型可以减少垃圾的生成。

  • 尽量少使用 foreach 循环,在循环遍历的过程中,对于 IEnumerable 接口的对象,foreach 循环过程会产生垃圾。改用 for 循环是一种解决方法。

  • 减少 Lambda 表达式和闭包的使用:当它们引用局部变量时会生成垃圾。

  • 减少大型一次性内存分配,尽可能使用固定大小或者逐渐增长的数据结构。

  • 对于仍需要的大对象,避免经常设为 null,设为 null 后会产生大量垃圾回收。

以上就是 Unity 游戏开发中 GC 产生的一些常见原因,理解和遵循这些原则可以实现有效的内存管理,编写更优化的代码,减少垃圾产生,提升游戏性能。


http://www.kler.cn/news/233174.html

相关文章:

  • 题目练习(生死时速2.0版)
  • C#既然数组长度不可改变,那么如何动态调整集合类型数组大小,以便添加或删除元素?
  • 学习通考试怎么搜题找答案? #学习方法#微信#其他
  • Gradle IDEA 乱码
  • 图灵之旅--二叉树堆排序
  • Android 判断通知是进度条通知
  • 生成式人工智能攻击的一年:2024
  • 【Mybatis】从0学习Mybatis(2)
  • Electron基本介绍
  • [职场] 如何通过运营面试_1 #笔记#媒体#经验分享
  • centos7.9 安装rabbitmq 3.6.15 集群
  • MySQL的DDL语言
  • idea: 无法创建Java Class文件(SpringBoot)已解决
  • 部署一个在线OCR工具
  • [office] 怎么在Excel2003菜单栏自定义一个选项卡 #其他#微信#知识分享
  • Bean 的六种作用域
  • 破除Github API接口的访问次数限制
  • Android 车载应用开发之车载操作系统
  • Flink cdc3.0动态变更表结构——源码解析
  • Spring 开发 pom.xml 配置文件(通用配置)
  • C++类和对象(7)
  • 【k8s系列】(202402) 证书apiserver_client_certificate_expiration_seconds
  • 龙芯开启ssh服务——使用Putty连接
  • Web后端开发:事务与AOP
  • PHP、Python、Java 和 Go语言对比
  • 【详解】斗地主随机发牌项目
  • GeoServer 2.11.1升级解决Eclipse Jetty 的一系列安全漏洞问题
  • 突破编程_C++_基础教程(类的基础知识)
  • 解密输入输出迷局:蓝桥杯与ACM中C++/C语言常见问题揭秘
  • 【Java八股面试系列】JVM-常见参数设置