内存统计口径
来源:飞书 wiki(obj_token: CGfbdNnGEoB6mixJdSmc1ZHcn6c)
下载说明:本文档图片均来自权限保护的飞书 wiki,所有图片 token 和 shell 脚本附件均返回 403(MCP 当前身份无权读取 wiki 内嵌资源)。已将每张图片的 AI 自动描述保留为占位引用,需要查看原 图请打开飞书原文。共 38 张图片、1 个 shell 脚本附件、1 张白板流程图(内存基线思维导图)。
整机内存占用
💡 整机内存占用 = 静态预留内存 + 内核占用内存 + 非 Cached(oom_adj < 900) 进程的 Pss 总和
静态预留内存 = DDR大小 - memTotal - GCMA
GCMA 内存大小获取方式:
-
- 执行
mount -t debugfs none /sys/kernel/debug;挂载 debugfs
- 执行
-
- 先
cd /sys/kernel/mm/cma/;
- 先
-
- 遍历目录下每一个子目录
<region name>,cat <region name>/gcma,过滤出值为 1 的 region;
- 遍历目录下每一个子目录
-
cat /sys/kernel/debug/cma/<region name>/count;
-
- 将所有 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 有三种获取方式:
- dumpsys meminfo 中的 Kernel CMA 值;
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;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 未达标进程暂不内存基线
| 进程/子系统 | 基线类型 | 内存分类 | Qcom | MTK | XRing | 备注 |
|---|---|---|---|---|---|---|
| 进程 | 图形+DMA | GL | UNMAPPED=cat /sys/class/kgsl/kgsl/proc/<pid>/gpumem_unmappedMAPPED=cat /sys/class/kgsl/kgsl/proc/<pid>/gpumem_mappedGL_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_memoryXRing: adb shell cat /proc/xgpu/gpu_memory |
| 进程 | 图形+DMA | DMA(含 EGL) | dmabuf_dump | dmabuf_dump | dmabuf_dump | 通过 gralloc 等分配 dmabuf 内存:图形、多媒体、相机。 |
| 进程 | 图形+DMA | Native 堆图形内存 | 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 加载器,新一代图形 APIlibui # UI 基础库,图形基础类型定义libskia # Skia 2D 图形引擎 [新增]libnativewindow # Native Window 接口 [新增]HAL / AIDL android.hardware.graphics.allocator-V2-ndk # 图形内存分配器 AIDL HALandroid.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 渲染启动 |
| 进程 | 非图形非 DMA | 1、showmap <pid>2、从 showmap 结果中提取 /dev/kgsl-* 的 Pss 内存作为 GfxDev3、 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.Free | cachedPss = ADJ >= 900 的所有进程 Pss 之和 MoreCachedSize = meminfo.KReclaimable + meminfo.Buffers + meminfo.Cached CachedSize = MoreCachedSize - meminfo.Mapped | 小米:重复统计了 Adj >= 900 进程的 meminfo.Mapped; Google:未包含被进程 |
| Used RAM | = totalPss - cachedPss + kernelUsed | totalPss = 所有进程 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对象获取cachedSizeKb、freeSizeKb、zramKb、kernelKb等内存大小,以及cachedPss、freePss等内存使用情况。代码还对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_RECLAIMABLE和ION池等信息,还提及了在旧内核情况下的处理方式等。(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* size和const 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_exported和const 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_level和ro.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 赋值给 p→pid,遍历kMemtrackTypes.size()个类型,调用 memtrack_proc_get_type 函数获取类型相关信息,若返回值不为 0 则返回该值。最后调用 memtrack_proc_sanity_check 函数进行检查。(token:G4edb7Dg2omkMYxmvJEc9eFZnIb,下载失败 403)
📷 图片描述:一个 C++ 函数代码,名为
memtrack_proc_get_type,用于获取进程的内存跟踪类型。函数接收memtrack_proc_type *t、pid_t pid和MemtrackType type三个参数。首先获取IMemtrack代理服务,若失败返回 -1。接着调用服务的getMemory方法获取内存记录,若失败也返回 -1。最后遍历记录,将sizeInBytes和flags赋值给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_tflags 参数。首先初始化 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* size和const 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 的 gpumem(cat sys/class/kgsl/kgsl/proc/5796/gpumem_unmapped,393216 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_pid,cat 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)