Unity native engine object及内存回收的碎碎念

想细细研究下 native engine object,发现之前理解有误,不过 Unity 到最后也没说清楚,所以标题从探究换成了碎碎念。

前排提醒:本文主要内容为个人思考,未精细排版,且少图多字,观感不佳。
如果你是搜索引擎过来的,建议直接跳转到重新理解原生引擎对象标题处

起因

在 RenderTexture.Release 的文档中,Unity 官方有这么一句:

我从用 Unity 开始,对于Texture/RenderTexture这种 C# 对象都是这么理解的:它是对原生(OpenGL等)Texture的封装,真正的资源不是 C# 层面的东西,new 创建的资源占用的内存不会被被自动托管回收。

而 As with 这个词,一般翻译成和 xxx 一样,因此,这句话翻译成“和其他native engine object一样”应该是没问题的。

根据这句话,我想当然的理解成“Unity 有数种对原生资源的封装类型,他们统称为 native engine object”。进一步扩展,则理解成“对于这种封装原生对象的组件,需要时刻注意管理其内存,因为他们不会像托管类型一样被垃圾回收”。

然而,当我搜索native engine object的详细信息时,论坛上的 Unity 员工却说所有继承自UnityEngine.Object的都是native engine object,这让我的认知出现了混乱。

混乱根源

由于 native engine object 这三个字母太长了,下面用原生引擎对象代称。

Unity 员工原文是这么说的:

Native Unity Objects means any type that inherits from UnityEngine.Object.
Any such type can have a Managed Wrapper/Shell object used to communicate
with the native side from a script. That wrapper can get garbage collected,
but that won't cause the destruction of the native Object.

根据他的说法,所有继承自UnityEngine.Object的类型都是原生引擎对象,也就是说,常见的GameObjectComponment等都是原生引擎对象。

而我一直以为MeshTextureAudioClip这种才是原生引擎对象,仔细想想,可能是被 native 这个单词误导了。

重新理解原生引擎对象

上面那个 Unity 员工列出了原生引擎对象的 6 种场景:

翻译过来就是:

  1. 场景里本来就有的对象或运行时与场景关联的对象(例如运行时创建 GameObject 并放置于当前场景中),它们将在加载其他场景卸载本场景时清理,或者在卸载场景后调用 UnlaodUnusedAssets 时被清理;
  2. 通过 DontDestroyOnLoad 标记持久化的对象;
  3. 使用 new 创建的对象;
  4. 访问 .material 属性获取的对象;
  5. 实例化的 ScriptableObjects 等;
  6. 创建的 Texture/RenterTexture 或其他资源;

按照他的说法,我之前只是片面的将 6 的内容理解为原生引擎对象。

尝试重新理解原生引擎对象内存回收

接下来就需要理解(或者熟悉)这段话:

翻译下其内容:

对于除了 1 之外的内容,都需要自己对其进行生命周期管理,即手动调用Object.Destroy清理。

AddComponent将会把组件与GameObject关联,所以它会和GameObject的生命周期走,可以被自动卸载(不用手动清理)

卸载场景时自动清理的逻辑:旧的场景会被破坏性卸载,用来释放空间给新场景加载使用,此时会触发Resource.UnloadUnusedAssets。在卸载旧场景前,如果有些资源被下一个场景引用,那么卸载它们就会导致重新加载造成资源浪费。

你可以手动调用Resource.UnloadUnusedAssets,不过如果你只有一个场景,那么与场景一起加载的内容都会在内存中(除了实例化被销毁的动态内容)。

上面那段话不难理解,条理似乎也很清晰。

迷惑的点

论坛评论中有人提到,自己创建(new)的 Mesh 通过UnloadUnusedAssets也会被卸载。

而这就与上面说的不一致了。

老外的吐槽

老外的吐槽道出了痛点:

总的来说就是 Unity 的内存回收逻辑处于一个黑箱状态,我们只能自己去试验,且试验出来的结果与官方声称的结果可能对不上,对于和原生 C++、OpenGL 等相关的内存管理来说尤其如此,只能到最后头疼医头,脚疼医脚。

碎碎念与展望

我暂且还和原来一样,只手动处理 Mesh、Texture/RenderTexture 等的生命周期与内存释放好了,暂时不管其他东西。

至于官方,那位 Unity 员工的回复中说正在起草UnityEngine.Object内存相关的文档(2021.11.15),那就等等看吧。如上面吐槽第一条所说,希望 Unity 给个列表,说明哪些类型需要我们特别关注。

梓喵出没博客(azimiao.com)版权所有,转载请注明链接:https://www.azimiao.com/8671.html
欢迎加入梓喵出没博客交流群:313732000

我来吐槽

*

*

0位绅士参与评论

  1. Louis08-12 10:56 回复

    所以说如果用了RenderTexture,但在切换场景的时候没有去手动释放这个RenderTexture就会有问题了吧