内存分配器
Allocator负责管理应用程序的内存分配。例如,创建新节点时需要进行RAM分配。
默认情况下,标准系统malloc动态地在堆上分配内存。但是,使用标准分配器可能会导致性能下降:每次分配都需要额外的内存量。换句话说,操作系统存储有关内存分配的数据,这可能会消耗大量RAM。此外,标准系统分配器提供有关内存消耗统计信息的不准确信息。
这就是为什么UNIGINE除了标准系统malloc之外还提供自定义分配器。它在池中分配内存,使分配过程更快,更有效。此外,它还可以收集内存消耗的统计信息,包括分配总数和每帧分配数的信息。
内存池#
UNIGINE自定义分配器为分配提供了两个主内存池:静态和动态。
还有额外的实例池,用于存储开发人员定义的分配。通常,这些都是定期需要的分配。它们的工作方式与动态池相同,但实例池没有大小限制。
静态池#
静态池对于优化内存消耗至关重要。换句话说,在使用静态池时,每个分配消耗的额外内存大约为零。另外,它优化了分配本身,使它们更快。
配置静态池#
静态池受您应预先指定的大小值的限制。为此,您需要知道所需的内存量及其布局。简而言之,您需要知道每种类型(16,32,48字节等)要分配多少内存。例如,下图演示了四个静态池,其中包含16、32、48和64字节的分配:
静态池的配置应该为对应于最低规格的特定硬件完成。静态池设置存储在.boot配置文件中。
一般来说,过程如下:
- 在项目中,确定需要大量内存的位置。
- 设置您的项目,使其从此位置开始。
- 使用 -memory_statistics_enabled 1 命令行选项运行应用程序。它将启用收集池配置所需的内存统计信息。
仅当之前没有配置静态池时,才会收集统计信息。
- 在控制台中,运行memory_optimize_static_pools控制台命令以更新和优化静态池。
- 紧接着,运行boot_config_save控制台命令将静态池设置保存到.boot配置文件中,以便在下次应用程序启动时使用它们。
- 重新启动应用程序以使用更新的静态池配置。
动态池#
动态池也可以优化性能,但不能优化内存消耗。但是,它们仅受RAM大小的限制,这是一个优点。此外,动态池更灵活,因为它们可以根据需要扩展和缩小它们的大小。
配置动态池#
每个动态池存储特定类型的分配:16、32、48字节分配等。因此,您始终可以检查动态池中分配了多少每种类型的内存。这些值始终是16的倍数。例如,在下面的图片中,有16个不同大小的池:
要配置动态池,可以使用memory_dynamic_pool控制台命令。它通过指定分配的最大大小来定义动态池的数量。默认情况下,它设置为256字节,这意味着有16个池包含大小从16到256字节的分配。
分析池统计#
要获取有关所有已分配静态和动态内存池的信息,请使用memory_info控制台命令。
它将小分配的统计信息显示为一个表,其中每行对应一个内存池。
静态池分配 |
|
动态池分配 |
|
分配总数 |
表中的值提供了所有池中发生的所有内存分配的统计信息 |
显存分配#
除了自定义RAM分配器外,UNIGINE还提供了一个使用内存池管理VRAM分配的选项。
使用显存分配至少有两个原因:
- 默认情况下可分配的最小内存块为64Kb。为了避免为显着较小的图形资源(例如,需要少于64Kb的纹理)分配如此大量的内存,我们需要使用内存池。
- 分配的过程极其缓慢,因此我们必须提前分配显存,然后根据需要进行分配。
配置池#
有控制台命令允许您配置显存分配的池:
配置文件: | |
---|---|
描述:
| |
配置文件: | |
描述:
| |
配置文件: | |
描述:
|
配置块大小时,必须在峰值、性能和内存消耗之间找到平衡。块大小越大,帧率和性能越稳定,但内存消耗越大。因此,我们建议运行测试并微调值。
分析池统计#
要获取有关所有已分配显存池的信息,请使用video_memory_info控制台命令。它将为您提供以下信息:
Heap Default | 表中的值显示默认堆的统计信息,包括当前VRAM消耗、分配的VRAM量、池中的分配数等。 |
Heap Upload | 表中的值显示用于上载堆的统计信息。 |
Heap Readback | 表中的值显示用于回读堆的统计信息。 |
有关更多详细信息,请参阅本文。
分析分配#
UNIGINE提供有关RAM和VRAM使用和分配分析的统计信息。要访问此信息,请运行通用分析器并查看以下值:
RAM分配统计#
CPU ram free | 当前可用内存量。 |
CPU ram usage physics | 工作集的当前大小。工作集是当前在物理RAM中可见的内存页集(检查源)。 |
CPU ram usage committed | 内存管理器为正在运行的进程提交的私有内存总量(检查源)。 |
CPU ram malloc | UNIGINE自定义分配器分配的内存量。 |
CPU ram static pool | 静态池中分配的内存量。 |
CPU ram dynamic pool | 动态池中分配的内存量。仅适用于Windows。 |
CPU ram instance pool | 实例池中分配的内存量。 |
Frame Allocations | 每帧进行的分配数量。 |
Live Allocations | 运行时期间分配的当前/最大数量(峰值消耗)。 |
VRAM分配统计#
GPU vram free | 当前可用的显存量。 |
GPU vram usage | GPU使用的VRAM量。此值由图形驱动程序提供。 |
GPU ram usage | GPU使用的RAM量。此值由图形驱动程序提供。 |
GPU alloc | 引擎在GPU上进行的分配数量。 |
GPU Frame Allocations | 每帧进行的显存分配数。 |
GPU Live Allocations | 运行时期间分配的当前/最大数量(峰值消耗)。 |
GPU Allocator small pool size | VRAM池的最大大小。 |
GPU Allocator small usage | 显存池的实际使用情况。 |
GPU Allocator skinned | 为蒙皮网格分配的显存量。 |
GPU Allocator decals | 为贴花分配的显存量。 |
场景中的每个蒙皮网格都独立分配内存。蒙皮网格的VRAM在单独的池中以块的形式分配。UNIGINE允许通过skinned_mesh_pool_chunk_size控制台命令配置块的大小。默认情况下,它是64Mb。
贴花也是如此。要配置贴花的块大小,请使用decal_pool_chunk_size控制台命令。