Android内存解析<二>

本文从整体上对Android进程Memory的使用状况进行了分析,包括不同类型的进程(Java进程和Native进程)及其虚拟地址空间的特点。此外,还介绍了查看进程Memory状态的各种方法,并提供了深入分析单个进程Memory的具体手段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android进程Memory分析

前一篇总结中,我从整体上对Android平台各个模块Memory的使用状况进行了分析整理。这一篇,我再从Process的角度来分析单个进程的Memory使用状况。
Process Memory过大对我们是不利的,一方面资深用户如果发觉使用的App特别吃内存,则有被卸载的风险。另一方面App memory用量过大,当处于后台时会成为Low memory killer优先kill的的对象,导致用户再次回到你的App时用户体验会降低。因此,优化应用的memory还是值得关注的一个方向。

1. Process Memory基础

Android进程分为两种类型,一种是java process, 另外一种是纯粹的c/c++的native process。Java process运行在DVM之上,所以每个process中都会带有一个虚拟机。我们后面会看到java process所占用的memory整体会比native process大。(关于Java process memory管理的部分我后续再总结)

1.1. 虚拟地址空间

无论是java process还是native process, 站在linux process的角度来看,其线性地址空间是的一样的。我们先回顾下32位系统中进程memory的虚拟地址空间如下:

这里写图片描述

1.2 虚拟地址到物理地址
先介绍几个非常重要的概念,后续process内存分析都是在围绕其中的几个概念在做文章。

VSS : process占用的虚拟内存的大小
RSS:process实际占有的物理内存的大小,包括了与其他process共享的.so的内存
PSS:共享内存与其他process进行平摊后,该process实际占有的物理内存的大小
USS:process私有占用物理内存的大小,不包含共享库的内存

怎么理解上面这些概念呢?前面已经说明了process的虚拟地址空间,VSS就是在虚拟地址空间占用的memory, 比如malloc一块memory, 则虚拟空间中便宣称了一片内存空间;如果我们没有使用这块memory, 则process仅仅是在虚拟空间有了这块memory, 并没有分配到实际的物理空间,只有在访问这块memory时由于产生缺页中断才会真正的分配物理内存。RSS对应的也就是process中已经分配了的实际物理内存的大小。
给出一个简单的虚拟内存到物理内存的映射示意图如下:
A2和B2表示process A& Process B中使用了同一个共享库,因此在物理内存中对应了同一块区域。
process A对应的VSS大小是:A1 + A2 + A3
process A对应的RSS大小是:A1 + A2
process A对应的PSS大小是:A1 + A2/2
process A对应的USS大小是:A1

这里写图片描述

2. 查看所有Process的Memory状况
一般Android平台或者设备的厂家会关注当前系统中有哪些Process在运行,每个Process的Memory用量大致如何。往往会抓住Memory用量非常大的进程,看看是否异常以及是否有进一步优化的空间。

查看所有process memory状况的方式很多,我记录几种比较常见的方式:

2.1. adb shell ps
这种方式可以看到所有process的VSS以及RSS信息,而且user load上也可以使用。缺点是没有按size 排序,可以自己使用excel table按RSS的值再排序后进行分析。

这里写图片描述

2.2. adb shell procrank

这种方式缺点是在user load上不能抓到信息,只有各生产商内部RD们在eng的版本上才能分析。优点是各process的memory信息很清晰, 按PSS的大小进行了排序,可以很方便得关注到memory用量大的process以及你所关注的process的memory用量的排位状况。

这里写图片描述

2.3. adb shell dumpsys meminfo

这种方式与procrank一样可以看到PSS的信息,而且还可以根据Adj的分类来查看Memory. 比如你需要关注所有persistent process的memory状况,则可以很方面的从这里得到结果。

这里写图片描述

这里写图片描述

3. 深入分析单个Process的Memory状况
前面的一些command可以一次性把所有process的memory信息抓出来,从中我们可以初步的看到单个Process的memory信息,例如PSS, RSS等。如果想再深入看到更多详细的信息,我们可以使用如下一些方法。

3.1. dumpsys meminfo pid

通过这种方式我们可以了解到PSS各个部分的大小。另外Private Dirty基本上是RW的部分,Private clean则是RO的部分,从这些信息中,我们可以基本了解到一个Process的Memory大致占用状况。

这里写图片描述

3.2. cat /proc/pid/maps & cat /proc/pid/smaps

smaps则是更详细的分析手段,不过这种方式在user load下不能抓到信息,只有平台或者设备厂家的工程师们在eng load上才能一睹其芳容。
Linux中使用vm_area_struct来表示process的每一块虚拟memory,而smaps正是所有vm_area_struct的信息的汇总,是对Process虚拟空间中每块内存的详细描述。
我从网上copy了一张图过来进行说明,这里只是截取了smaps种某一段memory的描述:

这里写图片描述

第一行的各个字段整体描述了这一块内存的信息:

  • 虚拟内存的起始地址
  • 这块内存的属性:可读?可写?可执行?是否私有?
  • 偏移地址
  • 最后一项信息则说明了这段内存所属文件

    另外详细信息中的,

  • size则是这一块虚拟内存的大小
  • RSS和PSS则表明了这一块虚拟内存在物理内存中实际映射占有的空间

    如果对smaps更进一步分析,可以对vm的各段进行归类汇总:根据第一行的最后一项信息区分出该虚拟内存段是属于.so? stack? java heap?native heap?等等,这里我不再进行记录。

4. Process Heap分析
前面对process memory的分析基本上还是从整体上做分析,可以让process的开发者从整体上了解process运行时会占用多少的物理内存,或者更detail的了解到RO, RW, Heap等占用memory的状况。
对于Android App的开发者们更关注的是其中Heap的使用状况。这部分的工具也比较多,我总结两种分析的tool, 一种是Android Studio整合的Memory monitor,另一种介绍比较强大的MAT工具。

4.1. Android Monitor

Android Monitor的使用可以参考官网上的介绍,操作App的同时可以动态的观察Heap的变化。
https://developer.android.google.cn/studio/profile/investigate-ram.html#HeapDump

这里写图片描述

4.2. MAT (Memory Analyze Tool)

使用MAT之前,首先需要把Heap dump出来,方式比较多,例如DDMS的dump heap, 或者Android Studio中也可以dump heap, 或者使用adb shell am dumpheap命令也可以。例如我这边使用了Android Studio里面集成的dump heap功能:

这里写图片描述

把Heap file dump出来后,需要使用SDK中带的工具hprof-conv进行转换:hprof-conv heap-original.hprof heap-converted.hprof

这里写图片描述

最后使用MAT打开转换后的hprof文件,可以看到对应Process的Heap信息:最外面的饼图描述了Heap整体的大小,以及占用Memory比较大的一些对象。
这里写图片描述

或许你这里会有疑问,怎么上面看到的一个简单的Hello World的程序Heap会如此之大呢? 这是因为Android Java层的Process都是从Zygote fork出来的,所以每个Process都带有zygote相对应的Memory信息,导致Heap会非常大。但实际上App本身私自分配使用的Heap会小很多,我们可以在hprof-conv时加上-z 参数来得到相关的信息:hprof-conv -z heap-original.hprof heap-converted.hprof

这里写图片描述

这样再用MAT打开新的hprof文件,会发现Heap小了很多:

这里写图片描述

一般在分析Heap时,我们可以从dominator tree中进行分析,从Retained Heap一列可以看到各个对象占用Memory的状况。这样可以有针对性的对特别大的对象考虑是否有优化的空间。

这里写图片描述

如果你发现某些对象有异常,例如出现了泄漏没有被释放等,可以使用Path To GC Roots或者merge Shortest Paths to GC Roots来查看此对象被引用的路径。

这里写图片描述

这一篇总结从整体上对Android Process的Memory状况进行了分析,从中可以了解一个process RO, RW等细分类型的memory用量,另外对App开发特别关注的Heap总结了分析方法。下一篇我准备对Dalvik虚拟机对Java process memory的管理做下整理,希望后续对自己有帮忙。

<think>好的,用户问的是关于日志中的“<skip> mem guard”部分。首先,我需要回忆之前的历史对话。用户之前问过一条Android系统日志,里面提到了这个标签,我之前解释了整个日志的结构和原因,现在用户特别关注“<skip> mem guard”这一部分。 首先,我应该确认这个标签的含义。根据Android内存管理机制,当系统检测到内存不足时,会触发不同的处理级别。可能“mem guard”是指内存保护的某个阶段或阈值。而“<skip>”可能表示跳过了某个步骤,或者在这个情况下没有达到需要执行更严格的内存回收的条件。 接下来,需要拆解这个短语的组成部分。可能“mem guard”是内存保护机制的一部分,而“skip”说明当前的情况没有达到触发该机制的标准,因此系统跳过了进一步的回收动作。这可能意味着系统虽然需要回收内存,但还没有到必须采取紧急措施的地步。 然后,结合用户之前的日志内容,当时系统需要回收349MB的匿名内存,但当前可用内存是2010MB,触发阈值是2200MB。因此,系统可能处于一个预回收阶段,主动清理缓存进程,但还没有到必须使用更激进手段的时候。这时候“<skip> mem guard”可能表示跳过了更高优先级的回收动作,因为当前清理缓存进程已经足够,或者系统评估后认为暂时不需要进入更高级别的内存保护状态。 需要验证这个理解是否正确。查阅相关资料,比如Android内存管理的文档,确认“mem guard”是否是一个已知的机制。可能涉及Linux内核的lowmemorykiller或者Android的OOM Killer机制。当可用内存低于某个阈值时,系统会开始杀死进程,但不同的阈值对应不同的严重级别。“mem guard”可能对应某个特定的阈值等级,而“skip”意味着当前没有达到那个等级,所以不需要执行对应的操作。 另外,用户可能想知道这个标签是否意味着存在内存问题,或者是否需要担心。需要解释这是正常的内存管理行为,只有在频繁出现时才需要关注。同时,可能用户是应用开发者,关心自己的应用被杀死的原因,所以需要给出优化建议,比如减少内存占用,避免成为缓存进程中被优先回收的对象。 最后,总结“<skip> mem guard”的含义,说明系统在当前情况下跳过了某些内存保护机制,因为通过清理缓存进程已经足够释放所需内存,无需进一步操作。同时,强调这属于正常现象,除非频繁发生,否则无需特别处理。</think>\boxed{\text{“<skip> mem guard” 深度解析}} \boxed{\text{定义与作用}} `<skip> mem guard` 是Android内存管理机制中的**状态标记**,表示系统在本次内存回收时: 1. **未触发**强制性的内存保护(Memory Guard)机制 2. 当前内存压力**未达到**需要紧急终止进程的临界阈值 3. 系统仍处于**主动内存回收**阶段而非被动应急状态 \boxed{\text{技术原理}} $$ \begin{aligned} &\text{内存回收决策树} \\ &\quad \downarrow \text{可用内存 } \leq \text{triggerMemory(2200MB)} \\ &\quad \rightarrow \text{计算需回收量(349MB)} \\ &\quad \rightarrow \text{检查是否满足强制回收条件} \\ &\qquad \text{否} \rightarrow \text{标注} \color{red}{\text{<skip> mem guard}} \\ &\qquad \text{是} \rightarrow \text{触发lmkd杀进程} \end{aligned} $$ \boxed{\text{关键对比}} $$ \begin{array}{|l|l|l|} \hline \text{特征} & \text{<skip> mem guard} & \text{触发mem guard} \\ \hline \text{内存压力} & \text{中等(可预期)} & \text{高危(紧急)} \\ \text{回收策略} & \text{按ADJ优先级清理} & \text{强制终止任意进程} \\ \text{进程类型} & \text{仅缓存/后台进程} & \text{可能包含服务进程} \\ \text{系统响应} & \text{主动预防} & \text{被动抢救} \\ \hline \end{array} $$ \boxed{\text{典型场景}} 1. **应用切换时** - 启动Launcher(前台)需回收旧应用(后台)内存 - 但剩余内存仍高于`/proc/sys/vm/min_free_kbytes`设定的绝对下限 2. **内存预回收** - 系统预测即将需要更多内存(如打开大文件前) - 提前清理缓存进程避免未来卡顿 \boxed{\text{开发者注意要点}} - 当频繁出现`<skip> mem guard`时,提示: $$ \frac{\text{应用常驻内存}}{\text{设备物理内存}} \geq 15\% \quad \text{需优化内存占用} $$ - 应通过`adb shell dumpsys meminfo`监测关键指标: ```bash PSS # 实际物理内存使用量 SwapPss # 交换分区占用 GL Ctx # 图形内存开销 ``` 注:此标记属于Android内存管理的**正常优化行为**,表明系统正在智能平衡性能与内存利用率。仅当伴随`ANR`或`CRASH`时需重点排查。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值