Linux内存管理 -- /proc/{pid}/smaps讲解

本文详细解析了Linux系统中/proc/PID/smaps文件的内容及其字段含义,包括虚拟内存、物理内存分配、共享与私有内存等关键概念,并介绍了如何通过smaps文件深入理解Linux内存管理机制。

本文包括如下三部分:

  1. 基本介绍与输出介绍
  2. 第一行基础信息讲解
  3. 详细信息讲解
    3.1 Size
    3.2 Rss
    3.3 Pss、Shared/Private_Clean/Dirty
    3.4 Referenced
    3.5 Anonymous
    3.6 ShmemPmdMapped
    3.7 Shared/Private_Hugetlb
    3.8 Swap
    3.9 SwapPss
    3.10 KernelPageSize、MMUPageSize
    3.11 Locked
    3.12 THPeligible
    3.13 VmFlags

如果对Linux的内存管理机制没有了解过,建议先了解一下,便于理解:Linux内存管理

基本介绍

/proc/PID/smaps 文件是基于 /proc/PID/maps 的扩展,他展示了一个进程的内存消耗,比同一目录下的maps文件更为详细。

值得说明一下的是,每一个VMA(虚拟内存区域,即一个 vm_area_struct 结构指向的内存区域)都有如下的一系列数据

 

08048000-080bc000 r-xp 00000000 03:02 13130      /bin/bash

Size:               1084 kB
Rss:                 892 kB
Pss:                 374 kB
Shared_Clean:        892 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         0 kB
Referenced:          892 kB
Anonymous:             0 kB
ShmemPmdMapped:        0 kB
Shared_Hugetlb:        0 kB
Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB
THPeligible:           0
VmFlags: rd ex mr mw me dw

第一行基础信息

在讲解字段含义之前,我们必须知道什么匿名映射
Linux 内存管理的进程用户态内存分布中提到过,映射分为文件映射和匿名映射。

文件映射就是磁盘中的数据通过文件系统映射到内存再通过文件映射映射到虚拟空间,这样,用户就可以在用户空间通过 open ,read, write 等函数区操作文件内容。至于实际的代码,open,read,write,close,mmap... 操作的虚拟地址都属于文件映射。

匿名映射就是用户空间需要分配一定的物理内存来存储数据,这部分内存不属于任何文件,内核就使用匿名映射将内存中的某段物理地址与用户空间一一映射,这样用户就可用直接操作虚拟地址来范围这段物理内存。比如使用malloc申请内存。

  • 08048000-080bc000 是该虚拟内存段的开始和结束位置
  • r-xp 内存段的权限,分别是可读、可写、可运行、私有或共享,最后一位p代表私有,s代表共享
  • 00000000 该虚拟内存段起始地址在对应的映射文件中以页为单位的偏移量,对匿名映射,它等于0或者vm_start/PAGE_SIZE
  • 03:02 文件的主设备号和次设备号。对匿名映射来说,因为没有文件在磁盘上,所以没有设备号,始终为00:00。对有名映射来说,是映射的文件所在设备的设备号。
  • 13130 被映射到虚拟内存的文件的索引节点号,通过该节点可以找到对应的文件,对匿名映射来说,因为没有文件在磁盘上,所以没有节点号,始终为00:00。
  • /bin/bash 被映射到虚拟内存的文件名称。后面带(deleted)的是内存数据,可以被销毁。对有名来说,是映射的文件名。对匿名映射来说,是此段虚拟内存在进程中的角色。[stack]表示在进程中作为栈使用,[heap]表示堆。其余情况则无显示。

第一行的信息完全同于在maps文件中输出的信息。对于不熟悉maps文件的读者可以先了解maps的字段的含义与实现机制。

详细信息

Size虚拟内存空间大小。但是这个内存值不一定是物理内存实际分配的大小,因为在用户态上,虚拟内存总是延迟分配的。这个值计算也非常简单,就是该VMA的开始位置减结束位置

延迟分配就是当进程申请内存的时候,Linux会给他先分配页,但是并不会区建立页与页框的映射关系,意思就是说并不会分配物理内存,而当真正使用的时候,就会产生一个缺页异常,硬件跳转page fault处理程序执行,在其中分配物理内存,然后修改页表(创建页表项)。异常处理完毕,返回程序用户态,继续执行。

Rss:是实际分配的内存,这部分物理内存已经分配,不需要缺页中断就可以使用的。
这里有一个公式计算Rss:
Rss=Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty

share/private:该页面是共享还是私有。
dirty/clean:该页面是否被修改过,如果修改过(dirty),在页面被淘汰的时候,就会把该脏页面回写到交换分区(换出,swap out)。有一个标志位用于表示页面是否dirty。

share/private_dirty/clean 计算逻辑:
查看该page的引用数,如果引用>1,则归为shared,如果是1,则归为private,同时也查看该page的flag,是否标记为_PAGE_DIRTY,如果不是,则认为干净的。

Pss(proportional set size):是平摊计算后的实际物理使用内存(有些内存会和其他进程共享,例如mmap进来的)。实际上包含下面private_clean+private_dirty,和按比例均分的shared_clean、shared_dirty。

举个计算Pss的例子:
如果进程A有x个private_clean页面,有y个private_dirty页面,有z个shared_clean仅和进程B共享,有h个shared_dirty页面和进程B、C共享。那么进程A的Pss为:
x + y + z/2 + h/3

Referenced:当前页面被标记为已引用或者包含匿名映射(The amount of memory currently marked as referenced or a mapping associated with a file may contain anonymous pages)。

Linux内存管理的页面替换算法里讲过,当某个页面被访问后,Referenced标志被设置,如果该标志设置了,就 不能将该页移出。

Anonymous:匿名映射的物理内存,这部分内存不来自于文件的内存大小。

ShmemPmdMapped:PMD页面已经被映射的共享(shmem / tmpfs)内存量。在官方文档中,这样解释:"ShmemPmdMapped" shows the ammount of shared (shmem/tmpfs) memory backed by huge pages.

Shared/Private_Hugetlb:由hugetlbfs页面支持的内存使用量,由于历史原因,该页面未计入“ RSS”或“ PSS”字段中。 并且这些没有包含在Shared/Private_Clean/Dirty 字段中。

Swap:存在于交换分区的数据大小(如果物理内存有限,可能存在一部分在主存一部分在交换分区)

SwapPss:这个我并没有找到对应解释,但从源码可以得知,计算逻辑就跟pss一样,只不过针对的是交换分区的内存。

 

static void smaps_pte_entry(pte_t *pte, unsigned long addr,
        struct mm_walk *walk)
{
    struct mem_size_stats *mss = walk->private;
    struct vm_area_struct *vma = walk->vma;
    struct page *page = NULL;

    if (pte_present(*pte)) {//----------------------------------页面在内存中
        page = vm_normal_page(vma, addr, *pte);
    } else if (is_swap_pte(*pte)) {//---------------------------页面被swap出
        swp_entry_t swpent = pte_to_swp_entry(*pte);

        if (!non_swap_entry(swpent)) {
            int mapcount;

            mss->swap += PAGE_SIZE;
            mapcount = swp_swapcount(swpent);
            if (mapcount >= 2) {
                u64 pss_delta = (u64)PAGE_SIZE << PSS_SHIFT;
               do_div(pss_delta, mapcount);
                mss->swap_pss += pss_delta; // --------- 如果引用超过1,就将均值加入swap_pss中
            } else {
                mss->swap_pss += (u64)PAGE_SIZE << PSS_SHIFT;// ------------ 直接加一个页大小
            }
       } else if (is_migration_entry(swpent))
            page = migration_entry_to_page(swpent);
    }

    if (!page)//----------------------------------------------如果页面不存在,就不用更新mss其他信息了;如果存在,调用smaps_account()更新mss。
        return;
smaps_account(mss, page, PAGE_SIZE, pte_young(*pte), pte_dirty(*pte));
}

KernelPageSize:内核一页的大小
MMUPageSize:MMU页大小,大多数情况下,和KernelPageSize大小一样。

Locked:常驻物理内存的大小,这些页不会被换出。

THPeligible:映射是否符合分配THP的条件。如果为true,则为1,否则为0。 它仅显示当前状态。

THP,透明大页(Transparent Huge Pages),RHEL 6 开始引入,目的是使用更大的内存页面(memory page size) 以适应越来越大的系统内存,让操作系统可以支持现代硬件架构的大页面容量功能。与标准大页的区别在于分配机制,标准大页管理是预分配的方式,而透明大页管理则是动态分配的方式。

VmFlags:表示与特定虚拟内存区域关联的内核标志。标志如下:

 

rd  - readable
wr  - writeable
ex  - executable
sh  - shared
mr  - may read
mw  - may write
me  - may execute
ms  - may share
gd  - stack segment growns down
pf  - pure PFN range
dw  - disabled write to the mapped file
lo  - pages are locked in memory
io  - memory mapped I/O area
sr  - sequential read advise provided
rr  - random read advise provided
dc  - do not copy area on fork
de  - do not expand area on remapping
ac  - area is accountable
nr  - swap space is not reserved for the area
ht  - area uses huge tlb pages
ar  - architecture specific flag
dd  - do not include area into core dump
sd  - soft-dirty flag
mm  - mixed map area
hg  - huge page advise flag
nh  - no-huge page advise flag
mg  - mergable advise flag

参考文章:
Linux官方文档
Linux smaps接口文件结构
linux proc maps文件分析
linux proc maps文件分析
匿名文件映射问题 (概念不清晰)
Linux中各种设备及设备号
Linux smaps接口文件结构
闲聊Linux内存管理(1)
Linux物理内存回收机制
Linux /proc/$pid/smaps的含义
Linux传统Huge Pages与Transparent Huge Pages再次学习总结
Linux内存管理 一个进程究竟占用多少空间?-VSS/RSS/PSS/USS
linux 内存查看方法:meminfo\maps\smaps\status 文件解析



作者:墨染书
链接:https://www.jianshu.com/p/8203457a11cc
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

<think>在分析Android ANR(Application Not Responding)时,`/proc/pressure/`目录下的文件(如`memory`、`cpu`、`io`)提供了系统资源压力的关键指标。这些指标有助于判断ANR是否由资源争用(如内存、CPU或I/O压力)引起。以下是对这些文件中数据的解读及判断异常的方法: ### 1. **资源压力文件的结构** 每个压力文件(如`/proc/pressure/memory`)包含三行数据,分别对应不同时间窗口的平均压力值: - **`some`行**:表示至少一个任务因资源不足而延迟的比例。 - **`full`行**:表示所有任务因资源不足而阻塞的比例(更严重的资源短缺)。 每行包含三个数值(以`total`开头),分别表示: - `avg10`:最近10秒的平均压力占比(百分比)。 - `avg60`:最近60秒的平均压力占比。 - `avg300`:最近300秒的平均压力占比。 示例格式: ``` some avg10=0.05 avg60=0.03 avg300=0.01 full avg10=0.01 avg60=0.005 avg300=0.001 ``` ### 2. **判断异常的方法** #### (1) **`/proc/pressure/memory`(内存压力)** - **异常信号**: - `some`行中`avg10 > 20%`:表示短期内较多任务因内存不足而延迟(需警惕)。 - `full`行中`avg10 > 5%`:表示有任务完全阻塞,可能触发ANR(如引用[2]中`kswapd0`占用90% CPU即由内存压力导致)。 - **关联分析**: - 结合`/proc/meminfo`检查剩余内存(`MemFree`)、缓存(`Cached`)及交换空间(`SwapFree`)。 - 若`kswapd0`(内核交换进程)的CPU占用率高,说明系统正在频繁回收内存。 #### (2) **`/proc/pressure/cpu`(CPU压力)** - **异常信号**: - `some`行中`avg10 > 80%`:表示CPU队列中有较多等待任务(如引用[3]中运行队列`nr_running`值高)。 - **关联分析**: - 检查`/proc/stat`的CPU空闲时间(`idle`)占比(如长期低于20%表示过载)。 - 结合ANR日志中的CPU使用率(如引用[2]显示`system_server`占73% CPU)。 #### (3) **`/proc/pressure/io`(I/O压力)** - **异常信号**: - `some`行中`avg10 > 50%`:表示I/O延迟显著。 - `full`行中`avg10 > 10%`:表示任务因I/O阻塞。 - **关联分析**: - 检查I/O等待时间(`/proc/stat`中的`iowait`值,持续高于10%为异常)。 - 查看进程的I/O使用量(`/proc/<pid>/io`)。 ### 3. **分析步骤** 1. **定位ANR时间点**:从ANR日志中提取精确的ANR发生时间。 2. **检查压力值**:在对应时间窗口内,观察`avg10`是否超过阈值。 3. **交叉验证**: - 对比`/proc/stat`、`/proc/meminfo`等文件。 - 检查系统日志中是否有`lowmemorykiller`或`kswapd`的异常活动。 4. **进程级分析**:结合ANR日志中的进程CPU使用率(如引用[2]),定位高负载进程。 ### 示例:引用[2]中的ANR分析 日志片段: ``` S00EAA9 08-06 09:35:24.170 ... CPU usage from 92780ms to 0ms ago: 90% 141/kswapd0: 0% user + 90% kernel 73% 1307/system_server: 33% user + 39% kernel ``` - **推断**: - `kswapd0`占90% CPU,表明内存压力极高(对应`/proc/pressure/memory`的`some`或`full`值可能超阈值)。 - `system_server`高CPU占用可能由内存回收或I/O阻塞间接引起。 ### 总结 - **内存压力**:关注`kswapd0`和`lowmemorykiller`日志,检查`/proc/pressure/memory`的`full`值。 - **CPU压力**:结合`/proc/stat`和进程的CPU使用率。 - **I/O压力**:监控`iowait`和`/proc/pressure/io`的`some`值。 若压力值持续超过阈值,表明系统资源瓶颈是ANR的主因,需优化应用资源使用或调整系统配置[^1][^2]。 §§相关问题§§ 1. 如何通过`/proc/stat`文件分析CPU负载? 2. ANR日志中`am_anr`事件的具体含义是什么? 3. 内存压力高时,Android系统的`lowmemorykiller`机制如何工作? </think> ### Android ANR分析中 `/proc/pressure/` 资源压力数据解析与异常判断方法 在ANR分析时,`/proc/pressure/`目录下的文件(`memory`、`cpu`、`io`)提供了系统资源压力的实时指标。以下是各文件的异常判断方法: --- #### 1. **/proc/pressure/memory(内存压力)** **数据结构**: ``` some avg10=0.05 avg60=0.03 avg300=0.01 full avg10=0.01 avg60=0.005 avg300=0.001 ``` - **`some`行**:部分任务因内存不足而延迟的比例 - **`full`行**:所有任务因内存不足而完全阻塞的比例 - `avg10/avg60/avg300`:最近10/60/300秒的平均压力占比(百分比) **异常判断**: 1. **`avg10 > 20%`**(短期高压):表示内存回收(kswapd)频繁触发 - 示例:引用[2]中`kswapd0`占90% CPU即为内存压力表现 2. **`full > 5%`**:任务阻塞风险高,可能直接导致ANR 3. **与日志关联**: - 检查`lowmemorykiller`日志(`dmesg`) - 结合`/proc/meminfo`的`MemFree`、`SwapFree`值 --- #### 2. **/proc/pressure/cpu(CPU压力)** **数据结构**: ``` some avg10=0.75 avg60=0.50 avg300=0.30 full avg10=0.10 avg60=0.05 avg300=0.02 ``` **异常判断**: 1. **`some.avg10 > 80%`**:CPU队列积压严重 - 对应引用[3]中`nr_running`(运行队列长度)值过高 2. **`full.avg10 > 15%`**:任务因CPU不足被完全阻塞 3. **交叉验证**: - 检查`/proc/stat`的`procs_running`和`idle`值 - 分析ANR日志中的CPU使用率(如引用[2]中`system_server`占73% CPU) --- #### 3. **/proc/pressure/io(I/O压力)** **数据结构**: ``` some avg10=0.30 avg60=0.25 avg300=0.15 full avg10=0.05 avg60=0.02 avg300=0.01 ``` **异常判断**: 1. **`some.avg10 > 40%`**:I/O延迟显著增加 2. **`full.avg10 > 8%`**:任务因I/O阻塞 3. **关联指标**: - 检查`/proc/stat`的`iowait`值 - 监控`mmcblk`(存储设备)的I/O等待时间 --- ### **综合分析方法** 1. **时间对齐**:将压力数据与ANR发生时间精确匹配(误差±1秒) 2. **阈值参考**: | 压力类型 | some.avg10临界值 | full.avg10临界值 | |----------|------------------|------------------| | Memory | 20% | 5% | | CPU | 80% | 15% | | I/O | 40% | 8% | 3. **根因定位流程**: ```mermaid graph TD A[ANR发生] --> B{检查/proc/pressure} B -->|memory超阈值| C[分析kswapd/oom] B -->|cpu超阈值| D[检查CPU负载和调度] B -->|io超阈值| E[检测存储性能] C --> F[优化内存] D --> G[优化CPU] E --> H[优化I/O] ``` > **注意**:需结合`/proc/stat`、`/proc/meminfo`及ANR日志中的进程CPU使用率(如引用[2])进行交叉验证,避免单一指标误判[^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值