Version: 6000.3
语言: 中文
原生内存介绍
自定义本机内存分配器

本机内存分配器

Unity 提供了多种分配器类型,其中每种类型代表以下关键因素的不同相对优先级:

  • 创建、访问和释放内存对性能的影响。
  • 跟踪内存使用情况的开销。
  • 线程访问安全。

如果应用程序有很多备用内存,它可以在加载时使用更快、内存密集型的分配器场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表
和框架。但是,应用程序的内存越有限,它必须更有效地使用可用内存,这通常意味着使用较慢的分配器。

为了帮助您为不同的项目获得最佳性能,您可以自定义 Unity 的分配器以适应每个应用程序的大小和要求。

本机内存分配器类型

Unity 使用不同的分配器类型,它们都使用不同的算法来组织内存。Unity 的内存管理器在不同区域使用这些分配器类型来有效地组织应用程序中的内存。您可以通过玩家设置设置,用于为 Unity 构建的最终游戏设置各种特定于玩家的选项。更多信息
请参阅术语表
窗口,或通过命令行。

不同类型的分配器如下所示:

分配器用法

每种分配器类型都有不同的算法,用于将分配拟合到内存块中,因此对于不同类型的分配很有用。分配之间的重要区别通常是持久性或分配生命周期,它决定了分配的位置。例如,长期(持久)分配将转到堆和存储桶分配器,而短期分配将转到线程安全的线性和线程本地存储分配器。

在代码中的某个位置进行分配时,Unity 会执行以下作:

  • 检查代码当前是否在主线程上运行:
    • 如果代码在主线程上运行,则使用主线程动态堆分配器。
    • 如果代码未在主线程上运行,则分配会阻止访问线程分配器。
  • 检查分配器的大小:
    • 如果分配的大小足够小,可以放入存储桶分配器中,并且有空间,则会在存储桶分配器中分配内存。
    • 如果分配大小对于存储桶分配器来说太大,或者没有空间,则使用动态堆分配器。

双线程分配器

双线程分配器用于较长的分配和需要在线程之间传递的分配,例如需要从主线程传递到呈现线程的图形分配。

分配器包含两个动态堆分配器:一个用于主线程的无锁分配器,另一个用于所有其他线程,用于锁定分配和释放。它还包含一个用于小型、长期分配的存储桶分配器。

默认情况下,Unity 会创建多个双线程分配器,包括 Main 和 Gfx 双线程分配器。文件缓存和分析器帮助您优化游戏的窗口。它显示了在游戏的各个领域花费了多少时间。例如,它可以报告渲染、动画制作或游戏逻辑所花费的时间百分比。更多信息
请参阅术语表
分配始终是动态堆分配

有关双线程分配器用法的示例,请参阅双线程分配器示例

动态堆分配器

动态堆分配器是主堆分配器。它使用两级隔离拟合 (TLSF) 算法来管理其内存。它用于大型、长期的分配以及无法放入存储桶分配器的分配。分配被划分为给定大小的内存块,根据需要请求这些内存块。分配必须小于半块。对于动态堆分配器来说,半块或更多的分配太大了,在这种情况下,Unity 会使用虚拟内存 API 进行分配。

有关动态堆分配器用法的示例,请参阅动态堆分配器示例

存储桶分配器

存储桶分配器是一个快速的无锁分配器,可执行小分配。双线程分配器使用存储桶分配器进行小型、长期的分配。这些分配可防止小型分配器对动态堆分配器进行碎片化。

存储桶分配器保留内存块用于分配。每个块分为 16 KB 的小节。这是不可配置的,也不会显示在用户界面中。每个小节都分为分配。分配大小是配置的固定大小的倍数,称为粒度。存储桶分配器具有给定大小的最大块数。

重要: 存储桶分配器在开发版本和发布版本之间的行为不同,因为开发版本开发版本包括调试符号并启用探查器。更多信息
请参阅术语表
.

有关存储桶分配器使用示例,请参阅存储桶分配器示例

线程本地存储堆栈分配器

线程本地存储 (TLS) 堆栈分配器用于每个线程的短期分配。它是最快的分配器。它由后进先出 (LIFO) 内存堆栈组成,这些堆栈指针将每个堆栈指针设置为 0 以清除内存。TLS 分配器主要用于Allocator.Temp分配,也可以来自用户编写的代码。

线程本地存储 (TLS) 堆栈分配器的默认块大小为平台 4 MB,Unity 编辑器为 16 MB。您可以自定义这些值。如果分配器使用量超过配置的块大小,Unity 会增加块大小。此增加的限制是原始大小的两倍。

理想情况下,TLS 堆栈分配器的内存分配的生存时间少于一帧,并且与其包含范围具有相似的生命周期。

由于 TLS 是堆栈分配器,因此交错分配和释放模式(例如,分配 a、分配 b、解除分配 a、分配 c、解除分配 b 等)可以对其进行分段并阻止分配器重置堆栈点下栈。这可能会导致它完全填满,而理论上有可用空间。

如果线程的堆栈分配器已满,则分配将回退到线程安全线性分配器

有关 TLS 堆栈分配器用法的示例,请参阅 线程本地存储堆栈分配器示例

线程安全线性分配器

线程安全线性分配器是 TLS 堆栈分配器的后备,它最多分配 16 个内存块。它使用先进先出 (FIFO) 算法为作业无锁分配工作缓冲区。完成后,作业将释放这些缓冲区。它主要用于Allocator.TempJob分配,其生命周期限制为 4 帧,它们也可以来自用户编写的代码。

此分配器分配内存块,然后在这些块内线性分配内存。可用区块保存在池中。当一个块已满时,分配器从池中获取一个新块。当分配器不再需要块中的内存时,它会清除该块,并且该块将返回到可用块的池中。快速清除分配以使块再次可用非常重要,因此作业的分配时间不应超过几帧。

如果所有内存块都已满,则分配将回退到主双线程分配器,这是一个速度慢得多的分配器。

有关线程安全线性分配器用法的示例,请参阅线程安全线性分配器示例

其他资源

原生内存介绍
自定义本机内存分配器