Linux内存管理--smaps文件详解

本文介绍了Linux系统中smaps文件的作用,它是查看进程内存使用情况的重要工具,涵盖了虚拟内存、驻留内存、VIRT、RES和SHR概念,以及如何通过smaps文件深入分析内存映射和可能遇到的问题,如内存泄漏和性能瓶颈。

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

smaps文件是Linux的proc文件系统提供的查看系统下运行进程内存使用情况的方法,Linux给每个进程都提供了一个这样的文件,学会查看并分析smaps文件有助于定位和解决诸如内存泄漏、性能瓶颈等内存资源相关问题。

一、内存的两个概念

了解smaps文件之前,需要先搞清楚Linux内存管理中的虚拟内存(Virtual Memory)和驻留内存(Resident Memory)这两个重要概念。

1、虚拟内存

首先需要强调的是虚拟内存不同于物理内存,虽然两者都包含内存字眼但是它们属于两个不同层面的概念。进程占用虚拟内存空间大并非意味着程序的物理内存也一定占用很大。虚拟内存是操作系统内核为了对进程地址空间进行管理(process address space management)而精心设计的一个逻辑意义上的内存空间概念。虚拟内存是逻辑意义上的内存空间,为了使程序能够在物理内存上运行,需要将虚拟内存映射到物理内存,这一功能由操作系统中页映射表来完成。

2、驻留内存

驻留内存,是指被映射到进程虚拟内存空间的物理内存。进程的驻留内存就是进程实实在在占用的物理内存。一般我们所讲的进程占用了多少内存,其实就是说的占用了多少驻留内存而不是多少虚拟内存。因为虚拟内存大并不意味着占用的物理内存大。

二、VIRT、RES和SHR内存        

Linux下常常使用top命令来查看进程内存使用情况,top命令中有VIRT、RES和SHR三种内存,三者代表的内存分别如下:

VIRT:已经映射到物理内存空间的部分和尚未映射到物理内存空间的部分总和。

RES:进程虚拟内存空间中已经映射到物理内存空间的部分的大小。

SHR:进程占用的共享内存大小。

其中,SHR内存存在的原因,是Linux动态库的使用,

我们写的程序会依赖于很多外部的动态库(.so),比如libc.so、libld.so等等。这些动态库在内存中仅仅会保存/映射一份,如果某个进程运行时需要这个动态库,那么动态加载器会将这块内存映射到对应进程的虚拟内存空间中。多个进展之间通过共享内存的方式相互通信也会出现这样的情况。

这么一来,就会出现不同进程的虚拟内存空间会映射到相同的物理内存空间。这部分物理内存空间其实是被多个进程所共享的,所以我们将他们称为共享内存,用SHR来表示。

通过top命令我们已经能看出进程的虚拟空间大小(VIRT)、占用的物理内存(RES)以及和其他进程共享的内存(SHR)。但是仅此而已,如果我想知道如下问题:

进程的虚拟内存空间的分布情况,比如heap占用了多少空间、文件映射(mmap)占用了多少空间、stack占用了多少空间?

进程是否有被交换到swap空间的内存,如果有,被交换出去的大小?

mmap方式打开的数据文件有多少页在内存中是脏页(dirty page)没有被写回到磁盘的?

以上这些问题都无法通过top命令给出答案,但是有时候这些问题正是我们在对程序进行性能瓶颈分析和优化时所需要回答的问题。针对这些问题,Linux的proc文件系统给出了解决方法,它给每个进程提供了一个smaps文件,通过分析该文件就可以一一回答以上问题。

三、smaps文件

1、smaps文件的概念

smaps文件是Linux的proc文件系统提供的一种可以查看内存资源使用情况的方法,Linux系统中运行的库、堆、栈等信息都可在smaps中查看。在Linux中,每一个进程都有其对应的smaps文件,它记录了该进程各种内存资源的详细使用情况。

在smaps文件中,每一条记录(如下图所示)表示进程虚拟内存空间中一块连续的区域。其中第一行从左到右依次表示地址范围、权限标识、映射文件偏移、设备号、inode、文件路径。详细解释可以参见understanding-linux-proc-id-maps。

接下来8个字段的含义分别如下:

• Size:表示该映射区域在虚拟内存空间中的大小。

• Rss:驻留内存大小,是进程当前实际占用的物理内存大小,包括进程独自占用的物理内存、和其他进程共享的内存。     

• Shared_Clean:和其他进程共享的未被改写的page的大小

• Shared_Dirty:和其他进程共享的被改写的page的大小

• Private_Clean:未被改写的私有页面的大小。

• Private_Dirty:已被改写的私有页面的大小。

• Swap:表示非mmap内存(也叫anonymous memory,比如malloc动态分配出来的内存)由于物理内存不足被swap到交换空间的大小。

• Pss:该虚拟内存区域平摊计算后使用的物理内存大小(有些内存会和其他进程共享,例如mmap进来的)。比如该区域所映射的物理内存部分同时也被另一个进程映射了,且该部分物理内存的大小为1000KB,那么该进程分摊其中一半的内存,即Pss=500KB。

2、查看smaps内存

Linux下使用如下命令查看smaps文件:

cat /proc/{pid}/smaps > smaps.txt

输出如下图所示

通过查看进程的smaps文件,可以获取进程每个内存映射块的详细信息,分析这些信息,可帮助定位和解决如内存泄漏、性能瓶颈等内存相关问题。

### Linux `proc` 下 `pid/smaps` 文件详解 #### 一、概述 在Linux操作系统中,通过读取 `/proc/[pid]/smaps` 文件可以获取指定进程的内存映射区域及其详细的资源占用情况。此文件提供了比常规 `/proc/[pid]/maps` 更加详尽的信息,不仅限于地址范围和权限设置,还包括每个VMA(虚拟内存区)的具体属性。 #### 二、如何访问 smaps 数据 为了保存某个特定进程ID为 `{pid}` 的smas信息到名为 `smaps.txt` 的文本文件中,可执行如下Shell命令[^1]: ```bash cat /proc/{pid}/smaps > smaps.txt ``` #### 三、主要字段解释 以下是部分重要条目说明: - **Rss**: 实际分配给该段落物理页框的数量(单位KB),即Resident Set Size的一部分; - **Pss (Proportional Set Size)**: 表示共享页面按比例分摊后的大小;对于完全私有的映像来说,其值等于RSS; - **Size**: 映射区域内总的字节数量; - **KernelPageSize** 和 **MMUPageSize**: 描述内核以及硬件层面所使用的页面尺寸; - **Private_Clean**, **Private_Dirty**, **Shared_Clean**, **Shared_Dirty**: 对应不同类型的干净或脏污状态下的独占/共享页面数; - **Referenced Pages**: 已经被引用过的页面数目; - **Anonymous**: 不关联任何磁盘文件的匿名映射空间大小; - **Heap**, **Stack**: 分别指向程序堆栈所在位置的数据块详情; - **File**: 如果存在,则表示当前VMA是由哪个具体文件创建而来,并给出相应路径名; - **Swap**: 当前已交换出去至swap分区中的数据量。 例如,在`smaps`文件里可能会看到这样的记录片段[^3]: ``` 7f8d9c0e4000-7f8d9c2a5000 rw-p 00000000 00:00 0 [heap] Size: 1966 kB Rss: 983 kB Pss: 983 kB ... ``` 这里展示的是关于进程堆(heap)的部分统计指标。 #### 四、特殊注意事项 值得注意的是,当涉及到多线程应用时,由于各个线程拥有独立的工作环境——包括但不限于各自的调用历史(call stack), 局部变量等,因此针对单一线程而言更精确的方式是从对应的子目录下去查找相关信息,比如 `[stack]` 就位于 `/proc/[pid]/task/[tid]/` 中[^2]. ```python import os def get_thread_stack_info(pid, tid): path = f"/proc/{pid}/task/{tid}/stat" with open(path) as file: content = file.read() return content.split(' ')[22] print(get_thread_stack_info(1234, 5678)) ``` 上述Python脚本展示了怎样提取某一线程(`tid`)所属进程(`pid`)的任务状态字符串里的第23项参数作为近似代表其栈指针的位置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值