Android 埋点信息分析——内存篇

源码基于:Android U

0. 前言

在前一篇《Android statsd 埋点简析》一文中简单剖析了Android 埋点采集、传输的框架,本文在其基础对埋点信息进行解析,来看下Android 中埋下的内存信息有哪些。

1. 通过代码剖析google 埋点内容

1.1 PROCESS_MEMORY_STATE

frameworks/base/services/core/java/com/android/server/stats/pull/StatsPullAtomService.javaint pullProcessMemoryStateLocked(int atomTag, List<StatsEvent> pulledData) {List<ProcessMemoryState> processMemoryStates =LocalServices.getService(ActivityManagerInternal.class).getMemoryStateForProcesses();for (ProcessMemoryState processMemoryState : processMemoryStates) {final MemoryStat memoryStat = readMemoryStatFromFilesystem(processMemoryState.uid,processMemoryState.pid);if (memoryStat == null) {continue;}pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, processMemoryState.uid,processMemoryState.processName, processMemoryState.oomScore, memoryStat.pgfault,memoryStat.pgmajfault, memoryStat.rssInBytes, memoryStat.cacheInBytes,memoryStat.swapInBytes, -1 /*unused*/, -1 /*unused*/, -1 /*unused*/));}return StatsManager.PULL_SUCCESS;}

getMemoryStateForProcesses函数:读取每个应用进程;

readMemoryStatFromFilesystem函数:读取/proc/<pid>/stat节点,解析pgfault(9)、pgmajfault(11)、rssInbytes(23) 数据;

统计数据有:

  • uid
  • processName
  • oomScore
  • pgmajfault
  • rss
  • cache(memcg)
  • swap (memcg)

1.2 PROCESS_MEMORY_HIGH_WATER_MARK

    int pullProcessMemoryHighWaterMarkLocked(int atomTag, List<StatsEvent> pulledData) {List<ProcessMemoryState> managedProcessList =LocalServices.getService(ActivityManagerInternal.class).getMemoryStateForProcesses();for (ProcessMemoryState managedProcess : managedProcessList) {final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid);if (snapshot == null) {continue;}pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, managedProcess.uid,managedProcess.processName,// RSS high-water mark in bytes.snapshot.rssHighWaterMarkInKilobytes * 1024L,snapshot.rssHighWaterMarkInKilobytes));}// Complement the data with native system processesSparseArray<String> processCmdlines = getProcessCmdlines();managedProcessList.forEach(managedProcess -> processCmdlines.delete(managedProcess.pid));int size = processCmdlines.size();for (int i = 0; i < size; ++i) {...}// Invoke rss_hwm_reset binary to reset RSS HWM counters for all processes.SystemProperties.set("sys.rss_hwm_reset.on", "1");return StatsManager.PULL_SUCCESS;}

该函数主要查询所有应用进程和native 进程的内存信息。

getMemoryStateForProcesses函数:读取每个应用进程;

readMemorySnapshotFromProcfs函数:读取/proc/<pid>/status节点,解析UidVmHWMVmRssRssAnonRssShmemVmSwap 数据。通过判定/proc/<pid>/status节点中是否有RssAnonRssShmemVmSwap数据排除 kernel 进程;

最后通过设置 prop 唤醒 rss_hwm_reset 程序,将VmHWM 清除。

统计数据有:

  • uid
  • processName / cmdline (native是cmdline)
  • VmHWM

1.3 PROCESS_MEMORY_SNAPSHOT

同上 HWM,统计每一个应用进程和native 进程的内存快照,区别在于这里另外统计了每个进程的 GPU 使用量:sys/fs/bpf/map_fpuMem_gpu_mem_total_map

统计数据有:

  • uid
  • processName / cmdline(native是cmdline)
  • pid
  • oomScore
  • rss
  • rss_anon
  • swap
  • rss_anon + swap
  • gpu memory
  • hasForegroundServices (native 为false)
  • rss_shmem

1.4 SYSTEM_ION_HEAP_SIZE

    int pullSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs();pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, systemIonHeapSizeInBytes));return StatsManager.PULL_SUCCESS;}

解析 sys/kernel/debug/ion/heaps/system 节点total 部分的数据。

1.5 ION_HEAP_SIZE

    int pullIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {int ionHeapSizeInKilobytes = (int) getIonHeapsSizeKb();pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, ionHeapSizeInKilobytes));return StatsManager.PULL_SUCCESS;}

调用 Debug.getIonHeapsSizeKb,详细可以查看 android_os_Debug.cpp

解析/sys/kernel/ion/total_heaps_kb

1.6 PROCESS_SYSTEM_ION_HEAP_SIZE

    int pullProcessSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs();for (IonAllocations allocations : result) {pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, getUidForPid(allocations.pid),readCmdlineFromProcfs(allocations.pid),(int) (allocations.totalSizeInBytes / 1024), allocations.count,(int) (allocations.maxSizeInBytes / 1024)));}return StatsManager.PULL_SUCCESS;}

readProcessSystemIonHeapSizesFromDebugfs解析sys/kernel/debug/ion/heaps/system 节点进程部分数据。

1.7 PROCESS_DMABUF_MEMORY

    int pullProcessDmabufMemory(int atomTag, List<StatsEvent> pulledData) {KernelAllocationStats.ProcessDmabuf[] procBufs =KernelAllocationStats.getDmabufAllocations();if (procBufs == null) {return StatsManager.PULL_SKIP;}for (KernelAllocationStats.ProcessDmabuf procBuf : procBufs) {pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,procBuf.uid,procBuf.processName,procBuf.oomScore,procBuf.retainedSizeKb,procBuf.retainedBuffersCount,0, /* mapped_dmabuf_kb - deprecated */0, /* mapped_dmabuf_count - deprecated */procBuf.surfaceFlingerSizeKb,procBuf.surfaceFlingerCount));}return StatsManager.PULL_SUCCESS;}

getDmabufAllocations函数主要是调用 dmabufinfo.cpp 中ReadProcfsDmaBufs函数获取进程dmabuf 信息。

统计数据有:

  • uid
  • cmdline
  • oomScore
  • total (KB)
  • inode count
  • surfaceflinger size (KB)
  • surfaceflinger inode cnt

1.8 SYSTEM_MEMORY

    int pullSystemMemory(int atomTag, List<StatsEvent> pulledData) {SystemMemoryUtil.Metrics metrics = SystemMemoryUtil.getMetrics();pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,metrics.unreclaimableSlabKb,           //meminfo.SUnreclaimmetrics.vmallocUsedKb,                 //meminfo.VmallocUsedmetrics.pageTablesKb,                  //meminfo.PageTablesmetrics.kernelStackKb,                 //meminfo.KernelStackmetrics.totalIonKb,metrics.unaccountedKb,metrics.gpuTotalUsageKb,metrics.gpuPrivateAllocationsKb,metrics.dmaBufTotalExportedKb,metrics.shmemKb,                       //meminfo.Shmemmetrics.totalKb,                       //meminfo.MemTotalmetrics.freeKb,                        //meminfo.MemFreemetrics.availableKb,                   //meminfo.MemAvailablemetrics.activeKb,                      //meminfo.Activemetrics.inactiveKb,                    //meminfo.Inactivemetrics.activeAnonKb,                  //meminfo.Active(anon)metrics.inactiveAnonKb,                //meminfo.Inactive(anon)metrics.activeFileKb,                  //meminfo.Active(file)metrics.inactiveFileKb,                //meminfo.Inactive(file)metrics.swapTotalKb,                   //meminfo.SwapTotalmetrics.swapFreeKb,                    //meminfo.SwapFreemetrics.cmaTotalKb,                    //meminfo.CmaTotalmetrics.cmaFreeKb));                   //meminfo.CmaFreereturn StatsManager.PULL_SUCCESS;}

totalIonKb:统计/sys/kernel/dmabuf/buffers下所有定义在 /dev/dma_heap 的 exporter的总大小;如果不支持dmabuf,那就统计/sys/kernel/ion/total_heaps_kb节点;

gpuTotalUsageKb:解析节点 /sys/fs/bpf/map_gpuMem_gpu_mem_total_map

gpuPrivateAllocationsKb:获取GPU private

dmaBufTotalExportedKb:统计/sys/kernel/dmabuf/buffers下dmabuf 总和;

unaccountedKb:meminfo.MemTotal - accountedKb;

accountedKb 包括:

meminfo.MemFree + zram + meminfo.Buffers + meminfo.active + meminfo.inactive + meminfo.Unevictable + meminfo.SUnreclaim + meminfo.KReclaimable + meminfo.VmallocUsed + meminfo.PageTables + meminfo.KernelStack + dmaBufTotalExportedKb + gpuPrivateAllocationsKb

1.9 VMSTAT

    int pullVmStat(int atomTag, List<StatsEvent> pulledData) {ProcfsMemoryUtil.VmStat vmStat = ProcfsMemoryUtil.readVmStat();if (vmStat != null) {pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,vmStat.oomKillCount));}return StatsManager.PULL_SUCCESS;}

只统计 oom_kill 的次数。

2. 通过看板剖析 google 埋点内容

2.1 RSS hwm

结合代码第 1.2 节应该是统计每个进程的 hwm,其中包含顺序、倒序显示,显示的数值应该是平均值 ± 体现最大值和最小值。

Metric details 有可能显示更多的分位数信息。

从看板数据来看,三方的应用占用内存较大,例如 com.tencent.ig 和 com.roblox.client,后期内存健康优化可以考虑三方应用给系统带来的压力,也需要确定应用在后台时的内存占用。这里可以优先查看这些进程的anon RSS + swap 的内存占用,确定是否存在内存泄漏。

2.2 P95 anon RSS + swap

结合代码第 1.3 节应该是统计每个进程的 anon RSS + swap 高于P95 的分布。

Metric details 可能有更多分位数的分布。

从看板数据来看,三方的应用占用匿名页内存较大,可能存在内存泄露的可能。可以查看details

anon RSS + swap 中包含leaked、unused 内存,这些都会swap out 到zram,需要限制这个阈值。

2.3 ION heap Size

这里应该统计的是dmabuf,结合代码第 1.8 节。

Distribution details 中可能有每个进程的 dmabuf 的分布。

从看板数据来看,有还有1% 的进程使用DMABUF超过了910M,需要通过details 进行细细确认进程占用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/392905.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BootStrap前端面试常见问题

在前端面试中&#xff0c;关于Bootstrap的问题通常围绕其基本概念、使用方式、特性以及实际应用等方面展开。以下是一些常见的问题及其详细解答&#xff1a; 1. Bootstrap是哪家公司研发的&#xff1f; 回答&#xff1a;Bootstrap是由Twitter的Mark Otto和Jacob Thornton合作…

脊髓损伤小伙伴的活力重启秘籍! 让我们一起动起来,拥抱不一样的精彩生活✨

Hey小伙伴们~&#x1f44b; 今天咱们来聊聊一个超级重要又温暖的话题——脊髓损伤后的锻炼大法来啦&#xff01;&#x1f389; 记住&#xff0c;无论遇到什么挑战&#xff0c;我们都要像打不死的小强一样&#xff0c;活力满满地面对每一天&#xff01;&#x1f4aa; 首先&#…

2024实验班选拔考试(热身赛)

比赛传送门 邀请码&#xff1a;2024wksyb A. 简单的数列问题 签到&#xff0c;记得开long long。 #include<bits/stdc.h> #define rep(i,a,b) for (int ia;i<b;i) #define per(i,a,b) for (int ia;i>b;--i) #define se second #define fi first #define endl …

【C#语音文字互转】.NET的TTS文本转语音合成

官方文档给出环境为Visual Studio 2017及以上&#xff1b;C#SDK为.NET4.8及以上 本文章环境介绍&#xff1a; Visual Studio 2022&#xff1b;C#SDK为.NET6.0 语音转文字请移步&#xff1a;【C#语音文字互转】C#语音转文字&#xff08;方法一&#xff09; 一. 启动 Visual Stud…

【OceanBase系列】—— OceanBase应急三板斧

作者&#xff1a; 花名&#xff1a;洪波&#xff0c; OceanBase 数据库解决方案架构师 目前随着OceanBase数据库越来越流行&#xff0c;社区已经有很多用户在生产环境使用了OceanBase&#xff0c;也有不少用户的核心业务用到了OceanBase数据库&#xff0c;在使用OceanBase数据库…

新址·新征程|美创科技北京中心喜迎乔迁

7月30日&#xff0c;北京暴雨倾城 连绵大雨和隆隆雷声 却像是在为一场新征程洗礼 这一天&#xff0c;我们迎来了重要的时刻 ——美创科技北京中心搬新家啦&#xff01; 新址&#xff1a;北京市海淀区庚坊国际大厦6层 喜迎新址&#xff0c;一场简单但喜气盈盈、温馨十足的乔…

【Python学习手册(第四版)】学习笔记16-函数基础

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文主要介绍Python中函数的基本概念&#xff0c;作用域以及参数传递&#xff0c;函数语法以及def和return语句的操作&#xff0c;函数调用表达式的行为&#xff…

Delphi5实现DLL的编写、调用

效果图 显式跟隐式调用差不多的&#xff0c;就重新画了窗体&#xff0c;画的有点粗糙。 DLL文件 DLL文件是一种包含了可执行代码的库文件&#xff0c;但它不能独立运行&#xff0c;必须由其他程序&#xff08;如EXE文件&#xff09;显式或隐式地加载并调用。DLL文件通常用于实…

全国地铁路线及站点SHP数据

数据是GIS的血液&#xff01; 我们在《126M全球手机基站SHP数据分享》一文中&#xff0c;为你分享过全球手机基站分布数据。 现在再为你分享全国地铁轻轨路线与站点SHP数据&#xff0c;你可以在文末查看该数据的领取方法。 全球地铁路线及站点数据 截至2023年12月31日&…

LAVIS在Mac,M1PRO芯片下的安装实战

LAVIS在Mac,M1PRO芯片下的安装实战 契机 ⚙ 本地想装个图片理解的大模型&#xff0c;看了下blip2感觉比较合适&#xff0c;macos安装的时候有点坑需要注意下&#xff0c;但是最终也无法使用mps加速&#xff0c;比较蛋疼。这里记录下安装步骤。 安装 LAVIS/projects/blip2 a…

【研发日记】Matlab/Simulink技能解锁(十二)——Stateflow中的两种状态机嵌套对比

文章目录 前言 项目背景 两级状态机 函数状态机 分析和应用 总结 参考资料 前言 见《【研发日记】Matlab/Simulink技能解锁(七)——两种复数移相算法》 见《【研发日记】Matlab/Simulink技能解锁(八)——分布式仿真》 见《【研发日记】Matlab/Simulink技能解锁(九)——基…

数据结构(其四)--特殊矩阵的存储

目录 11.特殊矩阵的压缩存储 &#xff08;1&#xff09;.一维数组的储存结构 &#xff08;2&#xff09;.二维数组的存储结构 &#xff08;3&#xff09;.普通矩阵的存储 &#xff08;4&#xff09;.特殊矩阵的压缩存储 i.对称矩阵 ii.三角矩阵 iii.三对角矩阵 iiii.稀疏矩…

Java多商户新零售超市外卖商品系统

解锁新零售奥秘&#xff0c;多商户外卖超市商品系统大揭秘&#xff01; &#x1f31f; 开篇&#xff1a;新零售时代的浪潮 在这个日新月异的数字化时代&#xff0c;新零售已悄然成为商业变革的新风口。想象一下&#xff0c;足不出户就能逛遍全城商家&#xff0c;心仪商品一键…

力扣——238.移动零

题目 思路 利用双指针&#xff0c;先找到第一个为0的地方指向&#xff0c;指针2指向下一个&#xff0c;指针1之前是已经处理好的数据&#xff0c;指针2进行遍历&#xff0c;遇到非零则与指针1数据交换&#xff0c;然后指针1。 代码 class Solution { public:void moveZeroes(…

离心机转子适配器容量转换器的作用

离心机转子是离心机的核心部件&#xff0c;离心机中的所有系统都配置为保证转子在一定条件下安全运行。转子不仅直接影响分离效果&#xff0c;而且也是离心机技术中的主要承力部件&#xff0c;对离心机的安全性极为重要。 简而言之&#xff0c;离心机可分为两部分&#xff1a;…

Java Web——第二天

什么是JavaScript? JavaScript(简称:JS) 是一门跨平台、面向对象的脚本语言。是用来控制网页行为的&#xff0c;它能使网页可交互 JavaScript和Java是完全不同的语言&#xff0c;不论是概念还是设计。但是基础语法类似 JavaScript在1995年由 Brendan Eich 发明&#xff0c;…

【MySQL】索引概念解析

1.什么是索引&#xff1f; MySQL中的索引是一种数据结构&#xff0c;用于帮助MySQL数据库管理系统快速查询数据。索引的主要目的是提高数据检索的速度&#xff0c;减少数据库系统需要扫描的数据量。 优点&#xff1a; 索引可以极大的提高数据检索效率&#xff0c;降低数据库…

C语言——预处理和指针

C语言——预处理和指针 预处理宏宏定义宏的作用域带参的宏 文件包含条件编译 指针指针的概念指针的定义 预处理 编程的流程分为&#xff1a;编辑、编译、运行、调试四个阶段&#xff1b; 预处理属于编译阶段&#xff0c;编译过程又可以分为&#xff1a;预处理、编译、汇编、链…

TikTok达人效应:品牌出海中的文化桥梁与本土化策略

在全球化的浪潮下&#xff0c;品牌出海已成为企业拓展市场的必经之路。然而&#xff0c;跨越文化差异、实现品牌本土化传播一直是企业面临的巨大挑战。TikTok作为一款全球流行的短视频平台&#xff0c;其庞大的用户基础和强大的影响力&#xff0c;为品牌出海提供了新的机遇。在…

大数据技术复习--大数据与云计算、物联网、人工智能

云计算 ** 概念&#xff1a;美国国家标准技术研究院“一种无处不在的、便捷的且按需的对一个共享的可配置的计算资源&#xff08;如网络&#xff0c;服务器、存储、应用和服务&#xff09;进行网络访问的模式&#xff0c;他能够通过少量的管理或服务供应商的互动实现计算资源的…