Unity 的托管内存系统是基于Mono 或 IL2CPP 虚拟机 (VM) 的 C# 脚本环境。托管内存系统的优势在于它管理内存的释放,因此您无需通过代码手动请求释放内存。
Unity 的托管内存系统使用垃圾收集器 和托管堆 在您的脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间推移修改组件属性并以任何您喜欢的方式响应用户输入。 更多信息
参见 术语表不再持有对这些分配的任何引用时自动释放内存分配。这有助于防止内存泄漏。内存泄漏发生在分配内存、对它的引用丢失,然后内存永远不会被释放,因为它需要一个引用来释放它。
此内存管理系统还保护内存访问,这意味着您无法访问已释放的内存,或您的代码永远无法访问的内存。但是,此内存管理过程会影响运行时性能,因为为 CPU 分配托管内存非常耗时。垃圾回收 也可能阻止 CPU 执行其他工作,直到它完成。
当调用方法时,脚本后端会将其参数的值复制到为该特定调用保留的内存区域,在一个称为调用栈的数据结构中。脚本后端可以快速复制占用几个字节的数据类型。但是,对象、字符串和数组通常要大得多,并且脚本后端定期复制这些类型的数据效率低下。
所有非空引用类型对象和托管代码中的所有装箱值类型对象必须分配在托管堆上。
熟悉值类型和引用类型非常重要,以便您可以有效地管理代码。有关更多信息,请参阅 Microsoft 关于值类型和引用类型的文档。
当创建对象时,Unity 会从称为堆的中央池中分配存储对象所需的内存,堆是 Unity 项目所选脚本运行时 (Mono 或 IL2CPP) 自动管理的内存区域。当不再使用对象时,它曾经占据的内存可以被回收并用于其他用途。
Unity 的脚本后端使用垃圾收集器自动管理应用程序的内存,因此您无需使用显式方法调用分配和释放这些内存块。自动内存管理比显式分配/释放需要更少的编码工作,并减少了内存泄漏的可能性。
托管堆是 Unity 项目所选脚本运行时 (Mono 或 IL2CPP) 自动管理的内存区域。
在上图中,蓝色框表示 Unity 分配给托管堆的一定数量的内存。其中的白色框表示 Unity 存储在托管堆内存空间中的数据值。当需要其他数据值时,Unity 会从托管堆(注释为A)的空闲空间中分配它们。
上图显示了内存碎片的一个示例。当 Unity 释放对象时,对象占据的内存会被释放。但是,空闲空间不会成为单个大型“空闲内存”池的一部分。
已释放对象两侧的对象可能仍在使用中。因此,空闲空间是其他内存段之间的“间隙”。Unity 只能使用此间隙存储大小相同或小于已释放对象的数据。
这种情况称为内存碎片。当堆中有大量可用内存,但它仅在对象之间的“间隙”中可用时,就会发生这种情况。这意味着即使有足够的总空间进行大型内存分配,托管堆也无法找到足够大的连续内存块来分配给该分配。
如果分配了一个大型对象并且没有足够的连续空闲空间来容纳它,如上所示,Unity 内存管理器将执行两个操作
堆的意外扩展可能存在问题。Unity 的垃圾回收策略往往会更频繁地碎片化内存。您应该注意以下几点
GC.Collect
以确保这些引用的状态是最新的。请记住UnloadUnusedAssets
不会自动触发,仅手动触发并在场景场景包含游戏环境和菜单。将每个唯一的场景文件视为一个唯一的关卡。在每个场景中,您放置环境、障碍物和装饰,本质上是分段设计和构建您的游戏。 更多信息UnloadUnusedAssets
或 GC.Collect
会触发一个 CPU 密集型过程,您可能希望在游戏过程中避免此过程。