Unity 0GC或者最大限度降低GC方案

文章目录

  • GC带来的问题
    • 性能瓶颈
    • 玩家体验受损
  • 优化关键点
    • 1. **对象池技术**:
    • 2. **内存管理优化**:
    • 3. **UGUI优化**:
    • 4. **ECS架构下的优化**:
    • 5. **资源管理**:
    • 6. **自定义数据结构与算法**:
    • 7. **开启增量GC(Incremental GC)**:
    • 8. **代码审查与性能分析**:
    • 9. **重用组件与MonoBehaviour实例**:
    • 10. **静态化与缓存**:
    • 11. **资源预加载**:
    • 12. **避免大型集合的操作**:
    • 13. **使用StructLayout.Pack / StructLayout.Explicit**:
    • 14. **弱引用与事件处理**:
    • 15. **自定义内存管理**:

Unity中垃圾回收(GC)频繁发生,会给游戏带来以下显著问题:

GC带来的问题

性能瓶颈

GC暂停主线程执行:当.NET的垃圾回收器开始工作时,它会暂时挂起所有程序执行以进行内存清理和整理。这意味着游戏逻辑、物理计算、渲染等都会被迫暂停,这会导致帧率下降或卡顿,影响游戏流畅度。
帧时间不一致:
由于GC的发生不可预知,其带来的延迟可能导致每一帧的时间长度不稳定,这对于实时交互的游戏体验尤其不利,特别是在需要保持稳定刷新率(如60fps)的场景。

玩家体验受损

突然的卡顿会影响玩家沉浸感,并可能导致在关键的游戏时刻出现响应延迟,比如战斗中的操作反馈或者复杂场景加载时的视觉表现。
资源浪费:
频繁的内存分配与回收也会增加系统的内存管理开销,导致整体系统效率降低,可能消耗更多的CPU周期和其他系统资源。
潜在的内存泄漏:
如果因为编程习惯不良而导致大量短生命周期对象不断产生并触发GC,则可能存在未被正确释放的内存,久而久之可能会引发内存泄漏,使得可用内存逐渐减少,最终导致游戏崩溃或其他严重问题。
因此,在Unity开发中,开发者需要密切关注代码设计,采用合适的数据结构、内存管理和对象池技术来最小化临时对象的创建和销毁,从而最大限度地减少对GC的依赖。

在Unity中实现0GC(零垃圾回收)的目标,主要是为了避免频繁触发.NET的垃圾回收机制,因为垃圾回收会导致短暂的帧率下降和性能波动。

优化关键点

1. 对象池技术

  • 对于生命周期短但创建销毁频繁的对象,如子弹、特效等,可以使用对象池来复用这些对象而不是每次需要时都创建新的实例。

2. 内存管理优化

  • 避免临时字符串或数组的频繁拼接,可使用预分配缓冲区或者专门设计用于无GC操作的字符串库(例如zstring或OneString)。
  • 长期使用的数据结构尽可能预先分配足够的空间,并避免动态扩容导致的内存碎片和GC压力。

3. UGUI优化

  • 在Unity UGUI开发中,确保对UI组件进行适当的缓存和重用,减少动态创建和销毁GameObject的行为。
  • 使用容器组件(比如CanvasScaler, LayoutGroup)时注意它们可能引发的不必要的布局计算和重建,采用UpdatePanelZeroAlloc这样的工具或方法来避免更新视图过程中的临时对象生成。

4. ECS架构下的优化

  • 使用Entity Component System (ECS) 架构,如Unity DOTS,通过实体和组件的集合式处理来降低GC负担。
  • 在ECS框架下,避免使用托管引用类型作为组件内容,转而使用值类型或结构体以保持堆栈分配。

5. 资源管理

  • 合理加载和卸载资源,利用AssetBundle和对象池策略减少运行时资源加载带来的内存分配。
  • 尽量避免大量小型纹理合并为 atlases 或使用Texture Atlas来减少内存碎片和GC调用。

6. 自定义数据结构与算法

  • 有时需要设计特定的数据结构和算法,使得它们在执行过程中不产生中间临时对象,从而避免GC。

7. 开启增量GC(Incremental GC)

  • Unity引擎支持开启增量GC模式,在某些情况下可以将垃圾回收的工作分散到多个帧上,减轻单次回收带来的卡顿感。

8. 代码审查与性能分析

  • 使用Unity Profiler或其他性能分析工具追踪内存分配情况,定位并修复内存泄漏问题以及不必要的内存分配来源。

总之,实现0GC是一个持续性的性能优化过程,需要结合具体项目情况进行细致的设计和调整。同时,虽然追求0GC是提升性能的一个手段,但在实际开发中往往难以完全避免GC,关键是合理管理和控制GC的影响范围及频率。

9. 重用组件与MonoBehaviour实例

  • 尽量复用MonoBehaviour脚本实例,避免在Update或FixedUpdate等频繁调用的方法内创建新对象。
  • 对于需要动态添加行为到游戏对象上的场景,可以考虑使用单例模式或者事件驱动机制代替临时对象。

10. 静态化与缓存

- 静态变量和全局缓存可以用于存储那些在整个游戏生命周期内都不会改变或只需创建一次的对象或数据结构。

11. 资源预加载

- 在游戏启动阶段预先加载所有必要的资源,并保持它们在内存中,而不是等到运行时再根据需求加载,这样可以减少因加载资源产生的临时对象。

12. 避免大型集合的操作

- 大型列表、数组或字典的添加、删除操作可能引发内部数组的重新分配。对于经常变动的数据集,可以采用合适的数据结构(如链表)或手动管理其容量来控制GC压力。

13. 使用StructLayout.Pack / StructLayout.Explicit

- 当使用结构体表示连续内存块时,可以利用`System.Runtime.InteropServices.StructLayoutAttribute`特性进行内存布局优化,确保没有空隙以防止GC对小对象池的影响。

14. 弱引用与事件处理

- 使用弱引用来监听事件可以减少由于强引用导致的对象无法被垃圾回收的问题。但要注意过度依赖弱引用可能导致逻辑复杂度增加,应在必要时谨慎使用。

15. 自定义内存管理

- 在极少数情况下,为了达到极致性能,可能需要通过unsafe代码或接口直接操作非托管内存,但这将极大地增加开发复杂性,且需具备深厚底层知识。

最后,请务必注意,尽管追求0GC有助于提升性能,但在实际项目中应权衡优化成本与收益,遵循“先做正确的事,再做快的事”的原则。同时,也要考虑到GC是.NET生态的重要组成部分,适当的GC工作对长期运行的程序是有益的,一味追求零GC并不总是最优解决方案。

python学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/329171.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三菱plc学习入门(二,三菱plc指令,触点比较,计数器,交替,四则运算,转换数据类型)

今天,进行总结对plc的学习,下面是对plc基础的学习,希望对读者有帮助,欢迎点赞,评论,收藏!!! 目录 触点比较 当数据太大了的时候(LDD32位) CMP比…

贯穿设计模式-享元模式思考

写享元模式的时候,会想使用ConcurrentHashMap来保证并发,没有使用双重锁会不会有问题?但是在synchronize代码块里面需要尽量避免throw异常,希望有经验的同学能够给出解答? 1月6号补充:没有使用双重锁会有问…

lv14 ioctl、printk及多个此设备支持 6

1 ioctl操作实现 对相应设备做指定的控制操作(各种属性的设置获取等等) long xxx_ioctl (struct file *filp, unsigned int cmd, unsigned long arg); 功能:对相应设备做指定的控制操作(各种属性的设置获取等等) 参数…

ssm基于Java Web的怀旧唱片售卖系统论文

摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装怀旧唱片售卖系统软件来发挥其高效地信息处理的作用&#x…

【STM32学习】硬件CRC与传统CRC-32计算的不同点

硬件CRC与传统CRC-32计算的不同点 1、stm32的硬件CRC32与传统CRC-32有何不同?2、解决办法 1、stm32的硬件CRC32与传统CRC-32有何不同? ①STM32F103的硬件CRC校验是对整个32位字进行CRC计算,传统的CRC-32是逐字节的计算。 ②STM32的硬件CRC32的…

C#,入门教程(09)——运算符的基础知识

上一篇: C#,入门教程(08)——基本数据类型及使用的基础知识https://blog.csdn.net/beijinghorn/article/details/123906998 一、算术运算符号 算术运算符号包括:四则运算 加 , 减-, 乘*, 除/与取模%。 // 加法,运算 int va 1 …

【JavaSE】Java中的反射动态代理

本篇文章整理的内容来源于: 反射原理 文章目录 一. 动态代理1. 优点2. 动态代理三要素3. 创建代理对象并使用 二. 反射1. 什么是反射2. 获取字节码文件对象的三种方式(1) Class.forName()获取 (源代码阶段)(2) 通过class属性获取(3) 通过对象获取字节码文件对象 3. 获取构造方…

LeetCode刷题11:滑动窗口解决1423.可获得的最大点数

几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。 每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。 你的点数就是你拿到手中的所有卡牌的点数之和。 给你一个整数数组 cardPoi…

网页设计与制作web前端设计html+css+js成品。电脑网站制作代开发。vscodeDrea 【企业公司宣传网站(HTML静态网页项目实战)附源码】

网页设计与制作web前端设计htmlcssjs成品。电脑网站制作代开发。vscodeDrea 【企业公司宣传网站(HTML静态网页项目实战)附源码】 https://www.bilibili.com/video/BV1Hp4y1o7RY/?share_sourcecopy_web&vd_sourced43766e8ddfffd1f1a1165a3e72d7605

c语言:用指针找出第一个相同的元素|练习题

一、题目 用指针&#xff0c;找出两数组中第一个相同的元素&#xff0c;并输入该元素 如图&#xff1a; 二、代码截图【带注释】 三、源代码【带注释】 #include <stdio.h> void f(); int main() { int a[5] {5,6,7,8,9}; int b[5] {6,4,6,8,3}; int *pa; …

工智能基础知识总结--什么是TextCNN

什么是TextCNN Yoon Kim在论文(2014 EMNLP) Convolutional Neural Networks for Sentence Classification提出TextCNN&#xff0c;该模型将卷积神经网络CNN应用到文本分类任务&#xff0c;是卷积神经网络应用到文本分析的开创性工作之⼀。 TextCNN的结构 TextCNN的结构图如下&…

【详解】静态库和动态库的认识和使用【Linux】

静态库和动态库的认识和使用 静态库和动态库的概述动静态库的实现静态库动态库库文件名称和引入库的名称 静态库和动态库的概述 静态库&#xff08;.a&#xff09;&#xff1a;程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库 动态库&#…