内存统计口径

来源飞书 wiki(obj_token: CGfbdNnGEoB6mixJdSmc1ZHcn6c)

下载说明:本文档图片均来自权限保护的飞书 wiki,所有图片 token 和 shell 脚本附件均返回 403(MCP 当前身份无权读取 wiki 内嵌资源)。已将每张图片的 AI 自动描述保留为占位引用,需要查看原 图请打开飞书原文。共 38 张图片、1 个 shell 脚本附件、1 张白板流程图(内存基线思维导图)。

整机内存占用

💡 整机内存占用 = 静态预留内存 + 内核占用内存 + 非 Cached(oom_adj < 900) 进程的 Pss 总和

静态预留内存 = DDR大小 - memTotal - GCMA

GCMA 内存大小获取方式:

    1. 执行 mount -t debugfs none /sys/kernel/debug;挂载 debugfs
    1. cd /sys/kernel/mm/cma/
    1. 遍历目录下每一个子目录 <region name>cat <region name>/gcma,过滤出值为 1 的 region;
    1. cat /sys/kernel/debug/cma/<region name>/count
    1. 将所有 gcma 为 1 的 region 的 count 值累加,最后乘以 4,单位为 KB。

内核占用内存 = Kernel(dumpsys meminfo 中 Used RAM: 中的 kernel 值)- Dma_unmaped(dumpsys meminfo 中 DMA-BUF: 的 unmapped 值)- GPU_private(dumpsys meminfo 中的 GPU: 的 private);它包含 kernelCmaUsage,若内核没有使能 CONFIG_CMA_FS,会导致 dumpsys meminfo 统计不到 CMA 的使用情况,内核内存就计算不准确。

内核占用内存也可以如下公式计算:

内核占用内存 = proc_meminfo.Shmem + proc_meminfo.SUnreclaim + proc_meminfo.VmallocUsed + proc_meminfo.PageTables + proc_meminfo.SecPageTables + proc_meminfo.KernelStack(当 CONFIG_VMAP_STACK 未使能时;其中 iQoo 已使能,小米 P1 已使能) + kernelCmaUsage(dumpsys meminfo 中的 Kernel CMA 值)

kernelCmaUsage 有三种获取方式:

  1. dumpsys meminfo 中的 Kernel CMA 值;
  2. cat sys/kernel/mm/cma/<region name>/alloc_pages_success - cat sys/kernel/mm/cma/<region name>/release_pages_success,累加 sys/kernel/mm/cma 所有子目录,最后 *4;
  3. cat /sys/kernel/debug/cma/<region name>/used,累加 /sys/kernel/debug/cma 的所有子目录,最后 *4;

进程 Pss 内存(root 版本) = dumpsys_meminfo.TOTAL - dumpsys_meminfo.graphics + Gpu_memory(GL) + DMA_buf。

📷 图片描述:进程 Pss 内存(root 版本)计算 shell 脚本预览(token: Xd4SbqkQLocnhLxYpyEct0DynFh,下载失败 403,属附件非图片)

内存基线统计规则

白板流程图(思维导图,token MQONw7mt6hKGLQbSzWWcO3TcnXg

整机内存基线有两个方案分支:

  • 方案一
    • 已达标部门内存基线
      • SR 已达标进程内存基线(按 OS4.0 实际占用基线)
        • 非图形非 DMA 内存基线(按 OS4.0 实际占用基线)
        • 图形 DMA 内存基线(按 OS4.0 实际占用基线)
    • 未达标部门内存基线
      • SR 已达标进程内存基线(按 OS4.0 实际占用基线)
        • 非图形非 DMA 内存基线(按 OS4.0 实际占用基线)
        • 图形 DMA 内存基线(按 OS4.0 实际占用基线)
      • SR 未达标进程内存基线(按 OS4.0 目标占用基线)
  • 方案二
    • 已达标部门内存基线
      • SR 已达标进程内存基线(按 OS4.0 实际占用基线)
        • 非图形非 DMA 内存基线(按 OS4.0 实际占用基线)
        • 图形 DMA 内存基线(按 OS4.0 实际占用基线)
    • 未达标部门内存基线(按 OS4.0 目标占用基线)
      • SR 已达标进程内存基线(按 OS4.0 实际占用基线)
        • 非图形非 DMA 内存基线(按 OS4.0 实际占用基线)
        • 图形 DMA 内存基线(按 OS4.0 实际占用基线)
      • SR 未达标进程暂不内存基线
进程/子系统基线类型内存分类QcomMTKXRing备注
进程图形+DMAGLUNMAPPED=cat /sys/class/kgsl/kgsl/proc/<pid>/gpumem_unmapped
MAPPED=cat /sys/class/kgsl/kgsl/proc/<pid>/gpumem_mapped
GL_KB = (UNMAPPED + MAPPED) / 1024
GL_KB = 4 * (cat /proc/mtk_mali/gpu_memory 2)GL_KB = 4 * (cat /proc/xgpu/gpu_memory 2)GPU 驱动分配的内存:BufferObject、GLcommand、GLTexture、MemPool、VBO
涉及的进程 pid:
Qcom:adb shell ls -l /d/kgsl/proc/
MTK:adb shell cat /proc/mtk_mali/gpu_memory
XRing:adb shell cat /proc/xgpu/gpu_memory
进程图形+DMADMA(含 EGL)dmabuf_dumpdmabuf_dumpdmabuf_dump通过 gralloc 等分配 dmabuf 内存:图形、多媒体、相机。
进程图形+DMANative 堆图形内存GPU 驱动
libGLESv2_adreno # Adreno GPU OpenGL ES 驱动
vulkan.adreno # Adreno GPU Vulkan 驱动
libadreno_ # Adreno GPU 相关库前缀
libgsl # Adreno GPU 内核接口库
libCB # Adreno Command Buffer,GPU 命令缓冲 [新增]
libRCC # Adreno 渲染/编译缓存 [新增]
libllvm-qgl # 高通 Shader 编译器 [已有]
libllvm-glnext # 高通新一代 Shader 编译器
Display HAL
mapper.qti # 高通图形内存映射器
libgrallocutilsng # 高通 Gralloc 工具库
libgralloc.qti # 高通 Gralloc 核心库 [新增]
libgralloc.system.qti # 高通系统 Gralloc [新增]
libgralloccore # Gralloc 核心库 [新增]
vendor.qti.hardware.display.snapalloc-impl # 高通 Snapdragon 显示分配
vendor.qti.hardware.display.config # 高通显示配置 HAL [新增]
libsdmcore # Snapdragon Display Manager 核心 [新增]
libsdmextension # SDM 扩展库 [新增]
libqservice # 高通显示服务 [新增]
eglSubDriverAndroid # EGL 子驱动(Android 适配)[新增]
libGLES_mali # Mali GPU OpenGL ES 驱动
vulkan.mali # Mali GPU Vulkan 驱动
GPU 驱动
libmtk_mali # MTK Mali GPU 驱动封装 [新增]
Graphics
mapper.mediatek # MTK 图形内存映射器 [新增]
libgralloc_extra # MTK Gralloc 扩展库 [新增]
libmtk_drvb # MTK 动态背光/对比度调节 [新增]
libmtk_colortm # MTK 色彩管理/色温映射 [新增]
libGLES_mali # Mali GPU OpenGL ES 驱动
vulkan.mali # Mali GPU Vulkan 驱动
mapper.xring # XRing 图形内存映射器
vendor.xring.hardware.display.composerext # XRing 显示 Composer 扩展 [新增]
vendor.xring.hardware.gamingplus # XRing 游戏图形增强 [新增]
GPU 驱动动态库和显示框架动态库分配的 native 内存,涉及的进程 pid 参考 GL;memuse 工具采集到 native unreleased 内存调用栈,过滤出 Android 图形显示框架、各芯片平台 gpu 驱动等 so,其中 Android 图形显示框架:
Graphics Framework
libhwui # Hardware UI 渲染,Android 2D 渲染核心
libgui # Surface/BufferQueue 框架,图形缓冲区管理
libEGL # EGL 接口层,OpenGL ES 与窗口系统桥梁
libGLESv1_CM # OpenGL ES 1.x 渲染 API [新增]
libGLESv2 # OpenGL ES 2.0/3.x 渲染 API [新增]
libvulkan # Vulkan 加载器,新一代图形 API
libui # UI 基础库,图形基础类型定义
libskia # Skia 2D 图形引擎 [新增]
libnativewindow # Native Window 接口 [新增]
HAL / AIDL
android.hardware.graphics.allocator-V2-ndk # 图形内存分配器 AIDL HAL
android.hardware.graphics.bufferqueue@ # BufferQueue HAL(HIDL,无 AIDL 替代,保留)[新增]
android.hardware.graphics.composer@ # 显示合成器 HIDL HAL [新增]
android.hardware.graphics.composer3 # 显示合成器 AIDL HAL [新增]
小米显示特性(XRing HyperOS 实测:SF / composer3-service.xring 直接加载)
vendor.xiaomi.hardware.display.mihwcextension # 小米 HWC 显示扩展 [新增]
vendor.xiaomi.hardware.displayfeature@ # 小米显示特性 HIDL HAL [新增]
vendor.xiaomi.hardware.displayfeature_aidl # 小米显示特性 AIDL HAL [新增]
vendor.xiaomi.hardware.framecapturemanager # 小米帧捕获管理(SF 加载)[新增]
vendor.xiaomi.hardware.framemaster # 小米帧主控(SF 加载)[新增]
小米画质增强 PQ(composer3-service.xring 直接进程加载,非 binder 客户端)
vendor.xiaomi.hardware.pqservice # PQ 服务 AIDL [新增]
vendor.xiaomi.hardware.prepqservice # 预 PQ 服务 AIDL [新增]
libpqservice # PQ 实现库 (/odm/lib64) [新增]
libprepqservice # 预 PQ 实现库 (/odm/lib64) [新增]
小米显示管理核心(XDM = Xiaomi Display Manager,composer 直接加载)
libxdmcore # XDM 核心 [新增]
libxdmresourcemanager # XDM 资源管理 [新增]
荣耀显示 HAL
vendor.honor.hardware.hwdisplay # 荣耀显示 HAL [新增]
vendor.honor.hardware.graphics.hwcinterface@ # 荣耀 HWC 接口 [新增]
vendor.honor.hardware.graphics.mediacomm@ # 荣耀媒体通信 [新增]
Pixelworks 显示芯片
vendor.honor.hardware.pixelworks_display@ # Pixelworks 显示芯片 HAL [新增]
vendor.honor.hardware.pixelworks_feature@ # Pixelworks 显示特性 [新增]
荣耀图形增强
vendor.honor.hardware.airenderlaunch # 荣耀 AI 渲染启动
进程非图形非 DMA1、showmap <pid>
2、从 showmap 结果中提取 /dev/kgsl-* 的 Pss 内存作为 GfxDev
3、Pss + SwapPss - Native 堆图形内存 - GfxDev
1、showmap <pid>
2、Pss + SwapPss - Native 堆图形内存
1、showmap <pid>
2、Pss + SwapPss - Native 堆图形内存
包括代码、数据、文件、线程栈、java 堆、native 堆及其他内存;但排除 native 堆图形内存和 GfxDev 内存
内核内核占用
内核驱动占用
内核进程占用
静态预留HLOS
静态预留器件
LostRAM

Dumpsys meminfo

Framework计算方式详情备注
Total RAM= meminfo.MemTotal
Free RAM= cachedPss + MoreCachedSize(原生 CachedSize) + meminfo.FreecachedPss = ADJ >= 900 的所有进程 Pss 之和
MoreCachedSize = meminfo.KReclaimable + meminfo.Buffers + meminfo.Cached
CachedSize = MoreCachedSize - meminfo.Mapped
小米:重复统计了 Adj >= 900 进程的 meminfo.Mapped;
Google:未包含被进程
Used RAM= totalPss - cachedPss + kernelUsedtotalPss = 所有进程 Pss 之和 - memtrack_graphics + dmabufMapped - memtrack_gls(当 gpuUsage 和 gpuPrivateUsage 都大于等于 0 时)
kernelUsed = meminfo.Shmem + meminfo.SUnreclaim + meminfo.VmallocUsed + meminfo.PageTables + meminfo.KernelStack(当 CONFIG_VMAP_STACK 未使能时;其中 iQoo 已使能,小米 P1 已使能)
+ ionUnmapped(当 ionHeap 和 ionPool 都大于等于 0 时;ionUnmapped = ionHeap - dmabufMapped)或 dmabufUnmapped(dmabufUnmapped = totalExportedDmabuf - dmabufMapped
+ gpuPrivateUsage(当 gpuUsage 和 gpuPrivateUsage 都大于等于 0 时)
+ kernelCmaUsage
华为 mate60 pro(鸿蒙 4.2 对应 android S):
totalPss = 所有进程 Pss 之和(Pss 仅包括 GL 内存)
kernelUsed = meminfo.Shmem + meminfo.SUnreclaim + meminfo.VmallocUsed + meminfo.PageTables + meminfo.KernelStack + gpuPrivateUsage(当 gpuUsage 大于 0 时)
其他友商竞品与小米一致
Lost RAM

📷 图片描述:Android 系统中 dumpsys meminfo 代码片段。当满足特定条件时,代码会获取内存相关信息并打印。关键部分是使用 memInfo 对象获取 cachedSizeKbfreeSizeKbzramKbkernelKb 等内存大小,以及 cachedPssfreePss 等内存使用情况。代码还对 lopts.isCompact 条件分支进行判断。(token: Rv1CbDdfooHxksxZGsccmgY7nZe,下载失败 403)

📷 图片描述:一段 C 语言代码,用于计算和打印内存相关数据。代码中定义了多个内存大小变量,如 ionHeap、ionPool、dmabufMapped 等。通过 if 条件判断,计算并打印出 ionHeap、ionPool、dmabufMapped 等内存大小,还计算了 totalExportedDmabuf、dmabufUnmapped 等内存值。代码最后还处理了 dmabufHeapExported 内存值。(token: Id8lbeMqcozGddxbLybcNwo7nqb,下载失败 403)

📷 图片描述:Android 系统中内存统计相关代码片段。代码用于获取和打印内存使用情况,包括 DMA-BUF Heaps、GPU 总使用量、GPU 私有使用量、Kernel CMA 使用量等。其中,DMA-BUF Heaps 使用了 Debug.getDbmbufHeapPoolsSizeKB() 方法获取,GPU 总使用量和私有使用量分别通过 Debug.getGpuTotalUsageKb()Debug.getGpuPrivateMemoryKb() 获取,Kernel CMA 使用量通过 Debug.getKernelCmaUsageKb() 获取。(token: I2fFbxPTYoiTzSx7a77cji87njc,下载失败 403)

📷 图片描述:Android 系统中与内存统计相关的代码片段。代码中定义了多个内存统计变量,如 lostRAM、kernelUsed 等,并对这些变量进行计算和输出。其中,lostRAM 通过减去其他内存值计算得出;kernelUsed 等于 kernelCmaUsage;kernelUsed 还与 kernelUsedSizeKb 等变量相关。代码最后还对这些内存值进行了打印输出。(token: KEXubjs60ogxIoxMwqOc65d6nYb,下载失败 403)

📷 图片描述:Android 系统中 Dumpsys meminfo 命令相关代码片段。代码在判断是否简要输出时,若不简要,会打印 ZRAM、Swap 等内存信息;若简要,仅打印 ZRAM、Swap 总大小。接着获取 ksm 信息,若 ksm 共享、不共享、可变信息不为 0,打印对应信息。最后获取进程列表的内存级别、缓存恢复阈值等信息。(token: TOnobVrZuoYOKnxyEN0c6CZCnQ6,下载失败 403)

📷 图片描述:Android 系统中 dumpsys meminfo 命令相关代码片段。代码中使用 if 语句判断 ksm 相关常量值,若满足条件则打印 ksm 相关信息,如 ksm 共享、ksm 共享未共享、ksm 未共享、ksm 可变等大小,以及 tuning 相关信息。还通过 ActivityManager 类获取内存类、大内存类等信息,以及 mProcessList 的 getLevel、getCacheRestoreThreshold 等值,判断设备是否为低内存或高内存设备等。(token: JOUBbqf27ofgZCxQHBqcWOqynOb,下载失败 403)

📷 图片描述:一段 Java 代码,涉及内存相关方法,如 getCachedSizeKb()getMoreCachedSizeKb()getKernelUsedSizeKb() 等。代码中对内存缓存大小获取及内核使用内存量计算等进行了定义,包含注释说明,如 MEMINFO_RECLAIMABLE 包含 MEMINFO_SLAB_RECLAIMABLEION 池等信息,还提及了在旧内核情况下的处理方式等。(token: AaHibNvJ4o9EqOxRfTocZue8nhg,下载失败 403)

ionHeap

📷 图片描述:Android 系统中 android_os_Debug_getIonHeapsSizeKb 函数的代码。该函数用于获取 Ion 堆的大小,以 KB 为单位返回。函数首先初始化 heapsSizeKb 为 -1,然后通过 meminfo::ReadIonHeapsSizeKb(&size) 调用内部函数读取 Ion 堆大小,若读取成功则将 size 赋值给 heapsSizeKb,最后返回 heapsSizeKb。(token: OtK0bDH5coTtnvxsB1LcSqQun2c,下载失败 403)

📷 图片描述:一个 C++ 函数代码片段,用于读取 ION 堆的分配大小(以 KB 为单位)。函数名为 ReadIonHeapsSizeKb,接受两个参数:uint64_t* size,用于接收分配大小;const std::string& path,可选参数,指定路径 /sys/kernel/ion/total_heaps_kb,默认为该路径。(token: NJuCbrGCqo7bhAxRojbcMf8Vnge,下载失败 403)

📷 图片描述:一个 C++ 函数代码片段,函数名为 ReadIonHeapsSizeKb,参数为 uint64_t* sizeconst std::string& path,返回值为 bool。函数内部调用了 ReadSysfsFile 函数。(token: VzK1bWg22oU5Pbxs9Tgc3m5nnJe,下载失败 403)

📷 图片描述:一个名为 ReadSysfsFile 的函数代码。该函数接收一个字符串类型的 path 参数和一个 uint64_t* 类型的 value 参数。函数首先调用 android::base::ReadFileToString 读取指定路径的文件内容,若读取失败则记录错误信息并返回 false。接着将读取到的内容转换为 uint64_t 类型赋值给 value,若转换失败同样返回 false。最后无论成功与否,函数均返回 true。(token: TMPXbcdgCocbiKx87sWcgMUGn0e,下载失败 403)

ionPool

📷 图片描述:Android 系统中 android_os_Debug_getIonPoolsSizeKb 函数的代码。该函数用于获取 Ion 池大小(以 KB 为单位)。函数首先初始化 poolsSizeKb 为 -1,然后通过 meminfo::ReadIonPoolsSizeKb 函数读取 Ion 池大小,若读取成功则将 size 赋值给 poolsSizeKb,最后返回 poolsSizeKb。(token: AAn1bo4gmouJ3TxPaVHc5zYZnjf,下载失败 403)

📷 图片描述:一个 C++ 函数代码片段,函数名为 ReadIonPoolsSizeKb,用于读取 ION 池分配大小(以 KB 为单位)。函数接受两个参数:uint64_t* size,用于接收读取到的大小值;const std::string& path,为读取路径,默认为 /sys/kernel/ion/total_pools_kb。(token: CBT4btAgVocDdHxJPUScKoYVnPb,下载失败 403)

📷 图片描述:主要是名为 ReadIonPoolsSizeKb 的函数,函数接收一个指向 uint64_t 类型的指针 size 和一个 const std::string& 类型的路径 path 作为参数,函数体内通过调用 ReadSysfsFile 函数,并传入 path 和 size 参数,最后返回 ReadSysfsFile 函数的执行结果。(token: RQIAbxaSno2N3ixu8wJcTisSnte,下载失败 403)

totalExportedDmabuf

📷 图片描述:Android 系统中 android_os_Debug_getDmabufTotalExportedKb 函数的代码。该函数用于获取总导出的 dmabuf 大小,以 KB 为单位。函数首先初始化 dmabufTotalSizeKb 为 -1,然后通过 dmabufinfo::GetDmabufTotalExportedKb(&size) 获取大小,若获取成功则将 size 赋值给 dmabufTotalSizeKb,最后返回。(token: Z6LEbVSDVodRAxxsEMec3PUYnU6,下载失败 403)

📷 图片描述:Android 系统中与 DMA-BUF 相关的函数代码。函数名为 GetDmabufTotalExportedKb,用于计算所有导出的 DMA-BUF 总大小,以 KB 为单位。该函数不读取或解析 DMA-BUF sysfs 统计的其余部分以提高性能。函数参数包括 uint64_t 类型的 total_exported 和 const std::string& 类型的 path,当前设置为 /sys/kernel/dmabuf/buffers。此函数仅用于单元测试,不供客户端使用。(token: B45pbv0EPoMlKLxufbpcrYvjn5d,下载失败 403)

📷 图片描述:一个 C++ 函数代码,用于获取 dmabuf_total_exported_kb 值。函数名为 GetDmabufTotalExportedKb,接受 uint64_t* total_exportedconst std::string& dmabuf_sysfs_stats_path 两个参数。代码首先打开指定路径的目录,若无法访问则返回 false。接着遍历目录内容,对每个项通过拼接路径读取其 /size 下的 size 值,累加到 total_exported 中。最后将 total_exported 除以 1024 并返回 true。(token: Ie1nb4FiPoma8SxKteWcnZNln1f,下载失败 403)

dmabufMapped

📷 图片描述:Android 系统中 android_os_Debug_getDmabufMappedSizeKb 函数的代码实现。该函数用于获取 DmaBuf 映射的大小。代码首先初始化 dmabufPss 为 0,然后通过 opendir 打开 /proc 目录,若失败则返回 false。接着循环读取目录中的文件,若文件类型为目录则跳过。将文件名转换为进程 ID,若 ID 为 0 则跳过。最后遍历 DmaBuf 信息,将每个 DmaBuf 的大小除以 1024 累加到 dmabufPss 中。(token: QTkJbyl1zoar8wxR4sncdO09nnf,下载失败 403)

📷 图片描述:一个 C++ 函数的代码片段,函数名为 ReadDmaBufMapRefs。该函数用于将特定进程的已映射 dmabuf 对象添加到现有向量中,若向量中已有匹配 inode 的元素,则更新引用计数。函数成功返回 true,否则返回 false。函数参数包括进程 ID、dmabuf 对象向量、procfs 路径和 dmabuf_sysfs 路径。(token: UlHTbvdOgoj6wmxn5P6ccspvnAb,下载失败 403)

📷 图片描述:一个名为 ReadDmaBufMapRefs 的函数代码,用于读取 dma_bufs 映射引用。函数接受进程 ID、std::vector<DmaBuffer*> 类型的 dmabufs、std::string 类型的 procs_path 和 dma_bufs_sysfs_path 参数。首先打开映射文件,若失败则返回 false。接着处理映射,若为 dma_buf,则处理映射到现有对象的引用;若未直接找到,尝试创建新对象并添加到 dmabufs。若为 FileDmaBuf,检查映射引用,若不为空则返回。若创建新 DmaBuffer,尝试从 sysfs 获取出口器名称,若成功则获取真实缓冲区大小,最后更新 DmaBuffer 引用。(token: P6zGblS4RoSbqixsE3vc1CJCnJN,下载失败 403)

📷 图片描述:一个 C++ 代码片段,用于处理内存统计相关数据。代码中使用 getline 函数逐行读取文件内容,若读取的行数据无法通过 android::procinfo::ReadMapFileContent 函数解析,将记录错误信息并返回 false。若所有行均能正常解析,则返回 true。该代码是 totalExportedDmabuf 统计口径中读取 /proc/self/maps 文件内容并解析的代码实现部分。(token: I1qbbRG4LoUfV8xMzz6cIL5Fn8c,下载失败 403)

gpuUsage

📷 图片描述android_os_Debug_getGpuTotalUsageKb 函数的代码。该函数接收 JNIEnv*jobobject 参数,用于获取 GPU 总使用量。代码中,先获取 sizeKb 变量,若 meminfo::ReadGpuTotalUsageKb 读取成功,则将 size 赋值给 sizeKb,最后返回 sizeKb。(token: O0kKbp9LRo3CokxI9m3cWefdnEf,下载失败 403)

📷 图片描述:一个 C 语言函数 ReadGpuTotalUsageKb 的代码。该函数接收一个 uint64_t 类型的指针参数 size,用于返回 GPU 总使用量。注释说明 gpu_mem_total tracepoint 将 PID 0 定义为全局总和,当前 Android 设备 GPU ID 0 即可满足需求,未来若设备有多个 GPU,需检查所有 GPU ID。函数通过调用 ReadProcessGpuUsageKb 函数来获取 GPU 总使用量。(token: KoK2bEiKcoO4TlxuQAiciOWinQf,下载失败 403)

📷 图片描述:一个 C++ 函数代码,用于读取 GPU 使用情况。函数名为 ReadProcessGpuUsageKb,接受 uint32_t 类型的 pid 和 gpu_id 参数。代码首先检查是否满足特定条件,然后定义常量 kBpfGpuMemTotalMap。接着通过 BpfMapR0 读取 GPU 内存使用情况,若读取成功则获取 gpu_mem 值,若失败则返回 0。最后,若 size 不为 0 则将其值除以 1024,函数返回 true。(token: H278bYLELoRyY6xdycMcFUkenug,下载失败 403)

gpuPrivateUsage

📷 图片描述:Android 系统中获取 GPU 私有内存的代码实现。代码首先检查是否支持 GPU 私有内存,然后创建 memtrack_proc 结构体,若失败则返回错误。接着获取 GPU 私有内存总量,若旧 HAL 实现不支持则返回 -1,否则返回内存值除以 1024。(token: TBgDbuS1lo53Knx2WdecTRsgnA1,下载失败 403)

📷 图片描述:一个 C++ 函数代码,用于判断 HAL 是否支持 GPU 私有内存。函数名为 halSupportsGpuPrivateMemory,首先获取 ro.product.first_api_levelro.build.version.sdk 的整数值,分别赋值给 productApiLevel 和 boardApiLevel。接着,通过 std::min 函数取两者最小值,判断其是否大于等于 _ANDROID_API_S_,最终返回判断结果。(token: LWprbZpoToLwOnxoqGZcrZfonkd,下载失败 403)

📷 图片描述:memtrack_proc_get 函数的代码。该函数接收 memtrack_proc 指针 p 和 pid_t 类型的参数 pid。首先检查 p 是否为 NULL,若为 NULL 则返回 -EINVAL。接着将 p 中 pid 赋值给 ppid,遍历 kMemtrackTypes.size() 个类型,调用 memtrack_proc_get_type 函数获取类型相关信息,若返回值不为 0 则返回该值。最后调用 memtrack_proc_sanity_check 函数进行检查。(token: G4edb7Dg2omkMYxmvJEc9eFZnIb,下载失败 403)

📷 图片描述:一个 C++ 函数代码,名为 memtrack_proc_get_type,用于获取进程的内存跟踪类型。函数接收 memtrack_proc_type *tpid_t pidMemtrackType type 三个参数。首先获取 IMemtrack 代理服务,若失败返回 -1。接着调用服务的 getMemory 方法获取内存记录,若失败也返回 -1。最后遍历记录,将 sizeInBytesflags 赋值给 t->records 数组对应位置。(token: F0m1bZx78oXYl2xtYo6cd08RnMd,下载失败 403)

📷 图片描述:一个 C 语言函数 memtrack_proc_gl_pss 的代码。函数接受一个 memtrack_proc 类型的指针参数 p,返回值类型为 ssize_t。在函数内部,先将 MemtrackType 中的 GL 类型存入 std::vector<MemtrackType> 类型的变量 types 中,然后调用 memtrack_proc_sum 函数,传入 p、types、以及 (uint32_t)MemtrackRecord::FLAG_SMAPS_UNACCOUNTED 作为参数。(token: DUXCbRk3qo3Wp8xI3Prct2JVn7c,下载失败 403)

📷 图片描述:一个 C++ 函数 memtrack_proc_sum 的代码。函数接受 memtrack_proc 指针 p、类型向量 types 和 uint32_t flags 参数。首先初始化 sum 为 0,接着遍历 types 向量,获取每个 type 对应的 records 向量,再遍历 records 向量,若 records[j].flags 与 flags 相等,则将 records[j].sizeInBytes 累加到 sum 中。最后返回 sum。(token: JfEmb3vrNoyRIsxqRAdc0f7BnHd,下载失败 403)

kernelCmaUsage

📷 图片描述:Android 系统中 android_os_Debug_getKernelCmaUsageKb 函数的代码。该函数用于获取内核 CMA(Contiguous Memory Allocator)的使用情况,单位为 KB。函数首先初始化 totalKernelCmaUsageKb 为 -1,接着调用 meminfo::ReadKernelCmaUsageKb 读取内核 CMA 使用大小,若读取成功则将读取值赋给 totalKernelCmaUsageKb,最后返回该值。(token: HoDnb18J4oClchxRAejcDdKVnFf,下载失败 403)

📷 图片描述:一个 C++ 函数代码片段,用于读取内核驱动程序通过 CMA 分配的内存总量,单位为 KB。函数名为 ReadKernelCmaUsageKb,参数包括 uint64_t* size 用于接收内存总量,以及 const std::string& cma_stats_sysfs_path,其默认值为 /sys/kernel/mm/cma,用于指定 CMA 状态的 sysfs 路径。(token: T7t6bdnt0oxdZvxCK7nc6JfznDg,下载失败 403)

📷 图片描述:一个 C++ 函数代码,用于读取 CMA 相关内存使用情况。函数名为 ReadKernelCmaUsageKb,接受 uint64_t* sizeconst std::string& cma_stats_sysfs_path 参数。代码中通过遍历目录获取 alloc_pages_success 和 release_pages_success 文件路径,分别读取其内容,计算并更新 totalKernelCmaUsageKb 变量,最后将 totalKernelCmaUsageKb 转换为 KB 并返回。(token: I5aVbUJTso3Vn8xuATCczZh9nbc,下载失败 403)

应用的 gpu 内存和 dma 内存

📷 图片描述:dumpsys meminfo 命令的输出结果,重点突出 Gfx dev、EGL mtrack、GL mtrack、Graphics 等内存相关数据。其中 Gfx dev 内存为 2424 KB,EGL mtrack 内存为 4848 KB,GL mtrack 内存为 384 KB,Graphics 内存为 7652 KB。(token: AH1WbrVeooKb83xZOUTcf3oInVq,下载失败 403)

💡 Dumpsys meminfo 中应用 GLmtrack 和 EGLmtrack 都是 Memtrack 通过各芯片厂商实现的 Hal 从内核节点中获取的。

📷 图片描述:Android 系统中获取应用 GPU 内存和 DMA 内存的流程图。从 dumpApplicationMemoryUsage 开始,经 getMemoryInfo 等步骤,最终通过 getGpuPrivateMemoryKb 获取 GPU 私有内存,再通过 android_os_Debug_getGpuPrivateMemoryKb 获取 GPU 私有内存 KB。流程中还涉及 Memtrack、MemtrackProxy 等对象,以及 HAL、JNI 等接口。(token: CpuIb9imdoF4XbxU4pqcEuv2nAl,下载失败 403)

  • GLmtrack

1)Qcom:仅统计了进程 unmapped 的 gpumemcat sys/class/kgsl/kgsl/proc/5796/gpumem_unmapped393216 Bytes = 384 KB,对应 dumpsys meminfo 截图中 GLmtrack)

📷 图片描述:在 Linux 系统中 cat 命令操作 sys/class/kgsl/kgsl/proc/5796 目录下 gpumem_unmapped 和 gpumem_mapped 文件的内容。其中,gpumem_unmapped 文件显示 393216 Bytes = 384 KB,对应 dumpsys meminfo 截图中 GLmtrack;gpumem_mapped 文件显示 13729792 Bytes = 13280 KB。(token: BvItblMFRodpjDxVrnJcZfuente,下载失败 403)

2)MTK:统计 kctx 的 used_pages(cat /proc/mtk_mali/gpu_memory | grep <pid>

3)Xring:统计 kctx 的 used_pages(cat /proc/xgpu/gpu_memory | grep <pid>

  • EGLmtrack

1)Qcom:统计进程分配的 ion 内存(cat /d/kgsl/proc/5796/mem | grep ion

📷 图片描述:在 Qcom 平台下,通过 cat 命令读取 d/kgsl/proc/5796/mem 文件,再 grep ion 过滤出相关内存信息的内容。显示了多个内存块的详细信息,包括 inode、wlb、type、surface、size 等参数,如 inode 为 708688 的内存块,type 为 ion,surface 为 23,size 为 998 等。(token: JBOZbD5P5oVN9Jxc1KlcsBiGnbe,下载失败 403)

2)MTK:统计进程正使用的按比例分摊的 dma 内存(echo "pid: <pid>" > proc/dma_heap/rss_pidcat proc/dma_heap/rss_pid,取 userspace_pss)

3)Xring:统计进程

  • dmabuf

dmabuf_dump 命令导出的结果中按 pid 匹配找到进程的 dmabuf 信息块,对比 EGLmtrack(例如:高通平台 cat /d/kgsl/proc/5796/mem | grep ion),可以看到完全被 dmabuf 包含(按 Inode 匹配)

📷 图片描述:Android 系统中 dmabuf_dump 命令导出的结果,按 pid 匹配找到进程的 dmabuf 信息块,对比 EGLmtrack 可以看到完全被 dmabuf 包含(按 Inode 匹配)。(token: NSIIb3b1Qov7nBxE5y7caBgsn1B,下载失败 403)

💡 为了准确评估应用业务的内存占用,需要将 gpu 内存和 dmabuf 内存按 showmap 的 Pss 内存分摊方式,归属给具体业务进程,请芯片厂商考虑修改 memtrack 统计方式,或评估是否认可如下计算方式(先剔除 memtrace 返回的 GL 和 EGL,然后通过从 kgsl 内核节点和 dmabuf_dump 命令获取 gpu 和 dmabuf 的 Pss 值):

进程 Pss 内存 = PSS(dumpsys) + SwapPss(dumpsys) - Graphic(dumpsys) + unmapped_gpumem(cat sys/class/kgsl/kgsl/proc/5796/gpumem_unmapped)+ mapped_gpumem(cat sys/class/kgsl/kgsl/proc/5796/gpumem_mapped) + dmabuf_pss(dmabuf_dump 结果中匹配进程 pid)