Skip to content

[Unity][MemoryProfiler] Executables & Mapped 实现原理分析 #46

Description

@nzcv

[Unity][MemoryProfiler] Executables & Mapped 实现原理分析

分析 Unity Memory Profiler 中 Executables & Mapped 分类的数据来源、分类逻辑、UI 展示方式,以及与 Unity 内部分配体系的关系。

整体数据流

flowchart TD
    A[Unity 运行时采集快照] --> B[SystemMemoryRegions<br/>Address/Size/Resident/Type/Name]
    B --> C[EntriesMemoryMapCache<br/>构建地址空间层次结构]
    C --> D[GetPointType<br/>Mapped → PointType.Mapped]
    D --> E1[AllMemorySummaryModelBuilder<br/>Summary 汇总]
    D --> E2[AllTrackedMemoryModelBuilder<br/>All Of Memory 树形展示]
    D --> E3[MemoryMapBreakdownModelBuilder<br/>Memory Map 着色]
Loading

1. 数据源:OS 级 System Memory Regions

快照格式版本 ≥ 16 时,会包含 SystemMemoryRegions 条目。类型枚举与 Unity 引擎 SystemInfoMemory.h 对齐:

public enum MemoryType : ushort
{
    // NB!: The same as in SystemInfoMemory.h
    Private = 0, // Private to this process allocations
    Mapped = 1,  // Allocations mapped to a file (dll/exe/etc)
    Shared = 2,  // Shared memory
    Device = 3,   // Shared device or driver memory (like GPU, sound cards, etc)
    Count
}

每个 region 包含:

字段 含义
RegionAddress / RegionSize 虚拟地址范围
RegionResident 驻留物理内存大小
RegionType OS 分类(Mapped = 1 即文件映射)
RegionName 文件路径(如 /path/to/libunity.so

由 Unity 运行时通过 OS API(如 VirtualQuery / /proc/self/maps 等)采集,Memory Profiler Editor 包只负责读取和展示。

2. 内存地图:地址空间层次结构

EntriesMemoryMapCache 把所有内存源叠成按地址排序的区间树:

  1. AddPoints:先加入 SystemMemoryRegion(OS 层,最底层)
  2. 再叠加 Unity 的 Native/Managed 分配
  3. SortPoints + PostProcess:建立父子嵌套关系

分类逻辑GetPointType 中:对 SystemMemoryRegion,读取 RegionTypeMapped 映射为 PointType.Mapped

var regionType = m_Snapshot.SystemMemoryRegions.RegionType[source.Index];
switch ((SystemMemoryRegionEntriesCache.MemoryType)regionType)
{
    case SystemMemoryRegionEntriesCache.MemoryType.Device:
        return PointType.Device;
    case SystemMemoryRegionEntriesCache.MemoryType.Mapped:
        return PointType.Mapped;
    case SystemMemoryRegionEntriesCache.MemoryType.Shared:
        return PointType.Shared;
    default:
        return PointType.Untracked;
}

Android 特例/dev/ 路径归为 Device,dalvik 相关归为 AndroidRuntime,不走 Mapped 分类。

3. 汇总统计(Summary Tab)

AllMemorySummaryModelBuilder 扁平扫描内存地图,按 PointType 累加:

case EntriesMemoryMapCache.PointType.Mapped:
    _summary.ExecutablesAndMapped += memorySize;
    break;

每个地址区间的 source 决定其分类。DLL/可执行文件映射区通常没有 Unity 子分配,整段都标记为 SystemMemoryRegion + Mapped;若 Mapped 区域内有 Unity 跟踪的分配,子区间会归为 Native/Managed,不会重复计入 Executables。

4. 明细展示(All Of Memory Tab)

AllTrackedMemoryModelBuilder.ProcessSystemRegion 按 region 名称分组:

case EntriesMemoryMapCache.PointType.Mapped:
{
    if (SearchFilter(args, k_ExecutablesGroupName, name))
        AddItemSizeToMap(context.ExecutablesName2SizeMap, name, size);
    break;
}

树结构示例:

Executables & Mapped (顶层分组)
├── libunity.so
├── GameAssembly.dll
├── mono-2.0-bdwgc.dll
└── ...

子项名称来自 OS 的 RegionName(文件路径);同名 region 会合并大小。

5. 与 Unity 内部分配体系的关系

Executables & Mapped 不在 Unity Memory Manager 跟踪范围内。

ProcessedNativeRoots 注释提到一个用于 Executables/DLL 的 fake root,但它没有对应分配,不会计入大小:

stuff like the first entry, which is the fake root for reporting the size of Executables & DLLS without any allocations actually rooted to it will remain with an invalid NativeObjectOrRootIndex and no sizes

因此:

  • Native / Managed:Unity 跟踪的堆分配、对象
  • Executables & Mapped:OS 报告的文件映射区(代码段、共享库、程序集等)
  • 两者数据源不同,统计口径也不同

6. 驻留内存(Resident Memory)

SystemMemoryResidentPages 时,ForEachFlatWithResidentSize 会按 region 计算驻留大小。Executables & Mapped 可同时显示 Allocated 和 Resident(代码页可能被换出,resident < allocated)。

7. 平台限制与 Legacy 行为

该指标并非所有平台一致报告:

情况 行为
SystemMemoryRegions 正常统计 Mapped 区域
SystemMemoryRegions(旧快照/部分平台) 该分类为 0 或缺失;总量用 TotalVirtualMemory 估算 Untracked
Android 部分路径被重分类为 Device / AndroidRuntime
控制台(PS/Switch 等) 统一内存架构下,部分"Native"实际可能是 GPU 内存

核心设计总结

维度 实现方式
识别依据 OS RegionType == Mapped(文件映射)
大小计算 地址空间扁平扫描,按区间 size = nextAddress - curAddress
分组键 RegionName(文件路径)
UI 入口 Summary 饼图、All Of Memory 树、Memory Map 着色
优化方向 提高 Code Stripping、减少模块/库依赖

本质:Unity Memory Profiler 把 OS 已分类的"文件映射内存"单独成类,用于展示应用二进制和依赖库占用的虚拟/物理内存;它不深入分析代码段内容,只依赖 OS 的 region 元数据(地址、大小、类型、文件名)。

关键源码路径

  • Editor/MemorySnapshot/Cached/SystemMemoryRegionEntriesCache.cs — OS region 类型定义
  • Editor/MemorySnapshot/Cached/EntriesMemoryMapCache.cs — 地址空间构建与 GetPointType
  • Editor/UI/Analysis/Breakdowns/Summary/Data/AllMemorySummaryModelBuilder.cs — Summary 汇总
  • Editor/UI/Analysis/Breakdowns/AllTrackedMemory/Data/AllTrackedMemoryModelBuilder.cs — All Of Memory 树形展示
  • Editor/MemorySnapshot/Cached/ProcessedNativeRoots.cs — fake root 说明(不计入大小)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions