GameObject 与 Native 组件(C++ 端):
1.每一个 GameObject,以及内置组件(如 Transform、MeshRenderer、Rigidbody 等),其核心数据结构都是用 C++ 实现的。
它们存在于 Unity 的 Native 内存 中,受 Unity 底层内存管理器控制,不由 C# 的垃圾回收器(GC)直接回收。
2.MonoBehaviour 与自定义脚本(Mono/IL2CPP 托管堆)以及脚本中定义的 C# 变量(如 int、string、自定义类对象等)是分配在 Mono 托管堆 上的,受 C# 的 GC 管理。
3.你的 C# 代码中访问一个 GameObject 时,会在mono上分配一个这个GameObject的wrap包装器,所以频繁地创建和销毁 GameObject(Instantiate / Destroy)会产生大量的 C# 包装器对象以及底层的Native内存分配。
4.如果你在 C# 中用静态变量强引用了 GameObject 或其组件的包装器,会导致底层的 Native 对象无法被 Unity 正常卸载,从而引发严重的内存泄漏。
5.Destroy(gameObject) 时Unity 会在当前帧的末尾销毁底层的 C++ 对象,并释放其占用的部分 Native 内存这部分内存会返回给 Unity 缓存(Cache),不会把释放的内存立即交还给操作系统(OS),你想强制 Unity 把未使用的 Native 内存交还给系统需要调用 Resources.UnloadUnusedAssets(),或者在场景切换时触发,这在移动端开销较大,不建议频繁调用。
6.gameobject被Destroy 触发后,C# 层的包装器(Wrapper)失去了底层 C++ 对象的支撑,变成了"死对象"(指向空指针)。但它们占用的托管堆内存依然被占用,只有当触发了 GC(Garbage Collection),Mono 内存管理器扫描到这些包装器不再被任何强引用持有时,才会将它们从托管堆中清理掉,腾出堆空间,但是 GC 释放了托管堆内存,Mono 堆的总大小(Heap Size)在移动端很少主动向 OS 归还堆内存,而是留着给后续的 C# 对象继续复用。
7.Texture 大头在Native 内存,即使你把 C# 层的 Texture2D 变量置为 null,如果底层的 Native 对象没有被 Destroy 或 Unload,这部分内存依然会被占用。在 C# 中你为了获取到的那个 Texture2D 对象本身的C# 包装器(Wrapper)是归属到托管堆,如果你通过 LoadAsset 获取了纹理实例,必须调用Resources.UnloadAsset(texture)这是释放单个纹理资源最标准的方法。它会立即卸载该资源在 Native 内存中的像素数据。