Unity GC优化整理

Unity GC优化整理

参考:
Unity优化之GC——合理优化Unity的GC:https://www.cnblogs.com/zblade/p/6445578.html
Unity GC 优化要点:https://www.cnblogs.com/u3ddjw/p/8624438.html
C# 入门(2) 预定义类型、用户定义类型、值类型和引用类型、可空类型:https://blog.youkuaiyun.com/l773575310/article/details/71082347
【Unity】中GC优化XLua下的各种值类型:https://blog.youkuaiyun.com/swj524152416/article/details/55511070
Unity中xLua与toLua对Vector3的优化:https://www.jianshu.com/p/07dc38e85923
C#技术漫谈之垃圾回收机制(GC):https://www.zhihu.com/search?type=content&q=c%23 gc 原理
Unity3D研究院之字符串拼接0GC(一百零四):http://www.xuanyusong.com/archives/4601

引用类型会产生GC

在这里插入图片描述

参数数组产生GC

// 数组(包括变长参数数组 params)会产生GC:
// Mathf库举例
public static int Min(params int[] values);
public static int Min(int a, int b);

// 如果调用是两个参数的Min方法,不会产生GC
Mathf.Min(1,2);			// 不产生GC

// 否则直接赋值整形会合成数组
Mathf.Min(3);			// 相当于Mathf.Min(new int[]{3}),创建个数组,产生40字节,加上一个int4个字节
Mathf.Min(new int[]{3});	// 和上面等价

List.ToArray 产生GC

List<int> intList = new List<int>() {};
intList.ToArray();		// 产生40字节GC

Input.touches 遍历输入

var a = Input.touches;  	//产生80字节

// 遍历的话直接调其API就好了
int count = Input.touchCount;
for (int i = 0; i < count; i++)
{
    var touch = Input.GetTouch(i);
}

参数为object的函数(会拆装箱)

// Vector3的一个比较方法:(5.6版本会有没有参数为Vector3的重载方法,下面是5.6版本会出现的GC情况)
public override bool Equals(object other);

Vector3 a, b;
a.Equals(b);		// b 从Vector3 装箱成object,产生GC
a == b;				// 代替上面,直接判断,不产生GC

字符串

  • 字符串合并,转换等都会产生GC,用StringBuilder,组件固定字符拆分多个组件。
  • 用插件zstring。

XLua优化

  • Vector3等这种 struct 结构体 要传给lua,会new一块userdata,拷贝一份数据出来,产生GC,优化方法可以是参数改成传三个float。
  • 自定义结构体改成class,就变成引用,不产生GC。
  • 枚举类型传的时候也会产生GC,可以用整形来传,再做转换。
  • 字符串,bytes,Unity和Lua互传就会产生GC,尽量避免。

Action (方法)

  • 作为参数,会拷贝。不要每帧调用,可以先存起来。

性能优化

  • 减少射线,如判断人物到地面高度,除了用射线,还可以用Terrain.SampleHeight来获取当前地形高度。
  • 降低复杂函数调用频率。
  • 频繁调用的变量先存起来。像gameObject.transform这种也要,在xLua会导出类似get_transform()的函数,每帧调用还是挺耗时的。
  • 打包的时候,屏蔽log。
  • 对象赋值,先判断是否相等,相等直接返回。
  • 少用协程。
### Unity GC 垃圾回收机制面试问题解析 #### 1. UnityGC的基本工作流程是什么? Unity使用的垃圾回收机制基于.NET运行时(CLR),其基本流程包括标记和压缩两个阶段。在标记阶段,GC会检查堆上的所有对象,并标记所有不可达的对象为待回收。随后进入压缩阶段,GC整理内存碎片,移动幸存的对象到连续的内存区域,并更新所有根的引用以指向新的内存位置。这一过程会暂停所有线程,确保回收的准确性[^2]。 #### 2. UnityGC的分代回收机制是如何工作的? UnityGC采用分代回收策略,将对象分为三代:第0代、第1代和第2代。新创建的对象属于第0代。当第0代内存达到阈值时,GC会回收第0代中的不可达对象,幸存的对象升级为第1代。当第1代内存达到阈值时,GC会同时回收第0代和第1代对象,幸存的第1代对象升级为第2代。第2代对象是长期存活的对象,只有在内存不足时才会触发完整的GC回收[^2]。 #### 3. 为什么频繁的GC会影响Unity游戏性能? 由于GC在标记和压缩阶段会暂停所有线程(Stop-The-World机制),频繁的垃圾回收会导致帧率下降,影响游戏的流畅性。此外,堆上的对象越多,对象之间的引用关系越复杂,GC需要处理的数据量越大,导致回收时间增加,进而加剧性能问题[^1]。 #### 4. 在Unity中如何优化GC的性能? - **避免频繁创建和销毁对象**:使用对象池(Object Pool)技术重用对象,减少GC的触发频率。 - **减少堆内存分配**:避免在Update等高频函数中分配临时对象,例如字符串拼接、LINQ查询等。 - **及时释放引用**:当对象不再使用时,将其引用置为`null`,以便GC能够识别为垃圾对象[^3]。 - **使用结构体代替类**:对于小型数据结构,优先使用结构体(值类型),避免堆内存分配。 - **避免循环引用**:使用弱引用(WeakReference)打破循环引用,防止对象无法被回收[^3]。 #### 5. UnityGC的触发条件有哪些? - **显式调用**:使用`System.GC.Collect()`强制触发GC,但不推荐频繁使用。 - **内存分配达到阈值**:当第0代对象的内存使用超过预算时,自动触发GC。 - **资源加载或卸载**:加载或卸载资源(如AssetBundle)时可能触发GC。 - **脚本编译**:在Editor中修改脚本并重新编译时,会触发GC以清理旧的类型信息。 #### 6. Unity中有哪些常见的GC优化技巧? - **字符串拼接优化**:避免使用`+`操作符拼接字符串,推荐使用`StringBuilder`减少临时字符串对象的创建。 - **协程与IEnumerator优化**:避免在协程中频繁使用`yield return new WaitForSeconds()`,可以使用共享的协程或自定义计时器。 - **匿名函数与闭包**:避免在频繁调用的函数中使用匿名函数或闭包,因为它们可能隐式捕获变量并延长对象生命周期。 - **使用Unity内置的容器类**:如`Unity.Collections`包中的`NativeArray`、`NativeList`等,它们在C# Job System中避免了GC分配。 #### 7. Unity中如何检测GC的性能影响? - **使用Unity Profiler**:通过Unity的Profiler工具监控`GC Alloc`指标,查看每帧的内存分配情况。 - **日志输出**:在Editor中启用`UnityEditorInternal.InternalEditorUtility.GetTotalAllocatedMemorySize()`等API,跟踪内存使用。 - **性能分析工具**:结合VisualVM、dotTrace等第三方工具分析C#堆内存的分配与回收情况。 ```csharp // 示例:使用StringBuilder优化字符串拼接 using System.Text; public class GCExample : MonoBehaviour { private StringBuilder sb = new StringBuilder(); void Update() { sb.Clear(); sb.Append("Frame: "); sb.Append(Time.frameCount); Debug.Log(sb.ToString()); } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值