linux的/proc/{pid}/maps介绍及使用(定位内存泄漏)

1、介绍

简单来说就是查看进程的虚拟地址空间是如何使用的。总共包括六列,每列及其含义如下。

address | perms | offset | dev | inode | pathname

(1)地址:本段在虚拟内存中的地址范围;对应vm_area_struct中的vm_start和vm_end。
(2)权限:本段的权限; r-读,w-写,x-执行, p-私有;对应vm_flags。
(3)偏移地址:即本段映射地址在文件中的偏移;对于有名映射指本段映射地址在文件中的偏移,对应vm_pgoff;对于匿名映射为vm_area_struct->vm_start。
(4)主设备号与次设备号:所映射的文件所属设备的设备号,对应vm_file->f_dentry->d_inode->i_sb->s_dev。匿名映射为0。其中fd为主设备号,00为次设备号。
(5)文件索引节点号:对应vm_file->f_dentry->d_inode->i_ino,与ls –i显示的内容相符。匿名映射为0。;
(6)映射的文件名:对有名映射而言,是映射的文件名,对匿名映射来说,是此段内存在进程中的作用。[stack]表示本段内存作为栈来使用,[heap]作为堆来使用,其他情况则为无。

关于更基础的地址空间划分、地址空间与mm_struct的管理 可以参照 这里  (很全面)!!!

其中涉及的task_struct, mm_struct , vm_area_struct等结构可以额外搜索文章详细了解,这里只做简要介绍。例如 这里
 

①task_struct:每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linux内核的进程控制块是task_struct结构体。

代码位置: 位置:<include\linux\sched.h> - 593行

部分代码如下:

struct task_struct
{
    /*...*/
	struct mm_struct		*mm;
	struct mm_struct		*active_mm;

	/* Per-thread vma caching: */
	struct vmacache			vmacache;
    /*...*/
}

②mm_struct:每一个进程都会有唯一的mm_struct结构体。

位置:<include\linux\mm_types.h> - 340行
部分代码如下:

struct mm_struct
{
    /*...*/
    struct vm_area_struct *mmap;		/* list of VMAs */
	struct rb_root mm_rb;
	u64 vmacache_seqnum;                /* per-thread vmacache */
    unsigned long mmap_base;	/*映射基地址*/
	unsigned long mmap_legacy_base;	/*不是很明白这里*/
    unsigned long task_size;	/*该进程能够vma使用空间大小*/
	unsigned long highest_vm_end;	/*该进程能够使用的vma结束地址*/
	pgd_t * pgd;
    atomic_t mm_users;
    atomic_t mm_count;
    int map_count;			/* vma的总个数 */
    unsigned long total_vm;	   /* 映射的总页面数*/
    /*...*/
    unsigned long start_code, end_code, start_data, end_data;
	unsigned long start_brk, brk, start_stack;
	unsigned long arg_start, arg_end, env_start, env_end;
    /*...*/

③vm_area_struct:内核每次为用户空间中分配一个空间使用时,都会生成一个vm_are_struct结构用于记录跟踪分配情况,一个vm_are_struct就代表一段虚拟内存空间。

位置:<include\linux\mm_types.h> - 264行
全部代码如下:

struct vm_area_struct {
	unsigned long vm_start; //虚存区起始
	unsigned long vm_end;   //虚存区结束
	struct vm_area_struct *vm_next, *vm_prev;   //前后指针
	struct rb_node vm_rb;   //红黑树中的位置
	unsigned long rb_subtree_gap;
	struct mm_struct *vm_mm;    //所属的 mm_struct
	pgprot_t vm_page_prot;      
	unsigned long vm_flags;     //标志位
	struct {
		struct rb_node rb;
		unsigned long rb_subtree_last;
	} shared;	
	struct list_head anon_vma_chain;
	struct anon_vma *anon_vma;
	const struct vm_operations_struct *vm_ops;  //vma对应的实际操作
	unsigned long vm_pgoff;     //文件映射偏移量
	struct file * vm_file;      //映射的文件
	void * vm_private_data;     //私有数据
	atomic_long_t swap_readahead_info;
#ifndef CONFIG_MMU
	struct vm_region *vm_region;	/* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
	struct mempolicy *vm_policy;	/* NUMA policy for the VMA */
#endif
	struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;

2、自测体验

(1)创建一个test.c文件,内容如下:

#include <stdio.h>
#include <stdlib.h>

int main()
{
        char *str;
        str = (char *) malloc(15);
        while(1)
        {
                ;
        }
        return 0;
}

(2)编译得到可执行文件

gcc test.c -o test

(3)明确进程号输出maps如下。

cat /proc/15204/maps
00400000-00401000 r-xp 00000000 fd:11 1573718                            /data/home/shuozhuo/test
00600000-00601000 r--p 00000000 fd:11 1573718                            /data/home/shuozhuo/test
00601000-00602000 rw-p 00001000 fd:11 1573718                            /data/home/shuozhuo/test
00a97000-00ab8000 rw-p 00000000 00:00 0                                  [heap]
7f312de71000-7f312de73000 r-xp 00000000 fd:01 794931                     /usr/lib64/libdl-2.17.so
7f312de73000-7f312e073000 ---p 00002000 fd:01 794931                     /usr/lib64/libdl-2.17.so
7f312e073000-7f312e074000 r--p 00002000 fd:01 794931                     /usr/lib64/libdl-2.17.so
7f312e074000-7f312e075000 rw-p 00003000 fd:01 794931                     /usr/lib64/libdl-2.17.so
7f312e075000-7f312e22d000 r-xp 00000000 fd:01 794815                     /usr/lib64/libc-2.17.so
7f312e22d000-7f312e42c000 ---p 001b8000 fd:01 794815                     /usr/lib64/libc-2.17.so
7f312e42c000-7f312e430000 r--p 001b7000 fd:01 794815                     /usr/lib64/libc-2.17.so
7f312e430000-7f312e432000 rw-p 001bb000 fd:01 794815                     /usr/lib64/libc-2.17.so
7f312e432000-7f312e437000 rw-p 00000000 00:00 0 
7f312e437000-7f312e457000 r-xp 00000000 fd:01 815248                     /usr/lib64/ld-2.17.so
7f312e53a000-7f312e53c000 rw-p 00000000 00:00 0 
7f312e54e000-7f312e551000 r-xp 00000000 fd:01 795444                     /usr/lib64/libonion_security.so.1.0.19
7f312e551000-7f312e651000 ---p 00003000 fd:01 795444                     /usr/lib64/libonion_security.so.1.0.19
7f312e651000-7f312e652000 rw-p 00003000 fd:01 795444                     /usr/lib64/libonion_security.so.1.0.19
7f312e652000-7f312e656000 rw-p 00000000 00:00 0 
7f312e656000-7f312e657000 r--p 0001f000 fd:01 815248                     /usr/lib64/ld-2.17.so
7f312e657000-7f312e658000 rw-p 00020000 fd:01 815248                     /usr/lib64/ld-2.17.so
7f312e658000-7f312e659000 rw-p 00000000 00:00 0 
7ffef4c96000-7ffef4cb7000 rw-p 00000000 00:00 0                          [stack]
7ffef4df7000-7ffef4df9000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

第一行的权限是只读,并且可执行,说明第一行是应用程序的代码段;

第三行的权限是可读可写,但是没有执行权限,说明该段是数据段。

第四行就是堆了。主要取决于程序中没有malloc之类的认为分配内存的语句。

3、用于协助定位内存泄漏

定位内存泄漏基本上是从宏观到微观,进而定位到代码位置。

从/proc/meminfo可以看到整个系统内存消耗情况,使用top可以看到每个进程的VIRT(虚拟内存)和RES(实际占用内存),基本上就可以将泄漏内存定位到进程范围。之前也大概了解过/proc/{pid}/maps,基于里面信息能大概判断泄露的内存的属性,是哪个区域在泄漏、对应哪个文件。辅助工具procmem输出更可读的maps信息。

其实对于微服务的场景,定位pid其实更简单;因为一般出问题的服务都是清楚的,其对应的进程也都是明确的,接下来就是查看这些pid的maps信息尝试找到线索就好了。

例如对于spp框架的C++微服务,在怀疑某服务可能内存泄漏的情况下ps即可找到对应pid。

查看其maps信息如下(不完全复制):

cat /proc/2558/maps
00400000-004a0000 r-xp 00000000 fc:01 912928                             /usr/local/services/spp_xxxx-2.3/bin64/spp_worker
005a0000-005a3000 rw-p 000a0000 fc:01 912928                             /usr/local/services/spp_xxxx-2.3/bin64/spp_worker
005a3000-007d6000 rw-p 00000000 00:00 0 
01eb8000-01ed9000 rw-p 00000000 00:00 0                                  [heap]
01ed9000-11c89000 rw-p 00000000 00:00 0                                  [heap]
7f90e673e000-7f90eb39f000 rw-s 00000000 00:04 2326599                    /SYSV00a6528e (deleted)
7f90eb39f000-7f90f0000000 rw-s 00000000 00:04 2424906                    /SYSV00a6528d (deleted)
7f90f0000000-7f90f0021000 rw-p 00000000 00:00 0 
7f90f0021000-7f90f4000000 ---p 00000000 00:00 0 
7f90f7d4f000-7f90f7d68000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7d88000-7f90f7da1000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7da1000-7f90f7dba000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7dba000-7f90f7dd3000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7dd3000-7f90f7dec000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7dec000-7f90f7e05000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7e05000-7f90f7e1e000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7e1e000-7f90f7e37000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7e37000-7f90f7e50000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7e50000-7f90f7e69000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7e69000-7f90f7e82000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7e82000-7f90f7e9b000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7ea2000-7f90f7ebb000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7ebb000-7f90f7ed4000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7ed4000-7f90f7eed000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7eed000-7f90f7f06000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7f06000-7f90f7f1f000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7f1f000-7f90f7f38000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7f38000-7f90f7f51000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7f51000-7f90f7f6a000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7f6a000-7f90f7f83000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7f83000-7f90f7f9c000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7f9c000-7f90f7fb5000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7fb5000-7f90f7fce000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7fce000-7f90f7fe7000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f7fe7000-7f90f8000000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f90f8000000-7f90f8045000 rw-p 00000000 00:00 0 
7f90f8045000-7f90fc000000 ---p 00000000 00:00 0 
7f90fc000000-7f90fc021000 rw-p 00000000 00:00 0 
7f90fc021000-7f9100000000 ---p 00000000 00:00 0 
7f9100000000-7f9100021000 rw-p 00000000 00:00 0 
7f9100021000-7f9104000000 ---p 00000000 00:00 0 
7f9104000000-7f91041a1000 rw-p 00000000 00:00 0 
7f91041a1000-7f9108000000 ---p 00000000 00:00 0 
7f9108000000-7f9108e02000 rw-p 00000000 00:00 0 
7f9108e02000-7f910c000000 ---p 00000000 00:00 0 
7f910c009000-7f910c022000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f910c022000-7f910c03b000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f910c03b000-7f910c054000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f910c054000-7f910c06d000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f910c06d000-7f910c086000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f910c086000-7f910c09f000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f910c09f000-7f910c0b8000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)
7f910c0b8000-7f910c0d1000 r--s 00000000 00:04 2457675                    /SYSV09998877 (deleted)

很显然其中的deleted看起来很奇怪。然后在代码中再搜一下 09998877 发现是shm的key。接下来的指向就很明确了,沿着这个方向继续查就好了。

猜你喜欢

转载自blog.csdn.net/mijichui2153/article/details/123934531