一 前言内存对于系统资源来说,非常重要,内存问题可以导致系统延迟增大,系统内存泄漏,进程被kill等多种严重问题,所以分析进程的内存占用很有必要 。本文重点分析了程序中动态申请内存的情况 。
注意所有测试是 5.13.0-52内核条件下测试的,不同的内核测试环境,内存分类会有很大的不同 。
二 程序内存结构在linux 32位系统中默认虚拟的内存布局如下:
文章插图
说明:VMA 是virtual Memory Area的简称,一个简单的程序VMA展示如下:
在linux中每个进程都有各自的虚拟内存空间,空间的大小和cpu的位数决定了虚拟空间的上限,比如在32位系统下,硬件可以访问的内存空间上限是4GB,这4GB的空间也不是完全可以给应用程序使用 。
整个内存空间分为两个部分,操作系统占用一部分,从地址0xC0000000到0xFFFFFFFF这1GB的空间 。剩下的从0x00000000到0xBFFFFFFF共3GB空间共3GB空间;
ELF可执行文件将整个虚拟内存空间分为多个segment;
操作系统是通过VMA 对进程的虚拟内存空间进行管理的 。
root@ubuntu-lab:/sys/kernel/debug/tracing# cat /proc/9776/maps5655a000-5655b000 r--p 00000000 fd:00 1193979/home/miao/c-test/mm-test/a.out5655b000-5655c000 r-xp 00001000 fd:00 1193979/home/miao/c-test/mm-test/a.out5655c000-5655d000 r--p 00002000 fd:00 1193979/home/miao/c-test/mm-test/a.out5655d000-5655e000 r--p 00002000 fd:00 1193979/home/miao/c-test/mm-test/a.out5655e000-5655f000 rw-p 00003000 fd:00 1193979/home/miao/c-test/mm-test/a.out5746c000-5748e000 rw-p 00000000 00:00 0[heap]f7d83000-f7da3000 r--p 00000000 fd:00 546008/usr/lib32/libc.so.6f7da3000-f7f1f000 r-xp 00020000 fd:00 546008/usr/lib32/libc.so.6f7f1f000-f7fa4000 r--p 0019c000 fd:00 546008/usr/lib32/libc.so.6f7fa4000-f7fa5000 ---p 00221000 fd:00 546008/usr/lib32/libc.so.6f7fa5000-f7fa7000 r--p 00221000 fd:00 546008/usr/lib32/libc.so.6f7fa7000-f7fa8000 rw-p 00223000 fd:00 546008/usr/lib32/libc.so.6f7fa8000-f7fb2000 rw-p 00000000 00:00 0 f7fbc000-f7fbe000 rw-p 00000000 00:00 0 f7fbe000-f7fc2000 r--p 00000000 00:00 0[vvar]f7fc2000-f7fc4000 r-xp 00000000 00:00 0[vdso]f7fc4000-f7fc5000 r--p 00000000 fd:00 546004/usr/lib32/ld-linux.so.2f7fc5000-f7fe8000 r-xp 00001000 fd:00 546004/usr/lib32/ld-linux.so.2f7fe8000-f7ff5000 r--p 00024000 fd:00 546004/usr/lib32/ld-linux.so.2f7ff6000-f7ff8000 r--p 00031000 fd:00 546004/usr/lib32/ld-linux.so.2f7ff8000-f7ff9000 rw-p 00033000 fd:00 546004/usr/lib32/ld-linux.so.2ffe18000-ffe39000 rw-p 00000000 00:00 0[stack]
说明:- 第一列VMA的地址范围;(虚拟地址)
- 第二列VMA的权限,r标识可读,w标识可写,x标识可执行,p 标识私有,s标识共享;
- 第三列偏移,表示VMA对应的Segment在映像文件中的便宜;
- 第四列一般表示映像文件所在设备的主设备号:次设备号,这里面主设备号大多显示为fd,难道是一个原因?非文件映射的内存,比如堆和栈,则这两位显示为00:00
- 第五列 标识映射文件的节点号;
- 第六列标识映射的具体文件,可以看到除了程序文件外,还有使用的库的文件信息 。vdso 为特殊的VMA,用于和内核进行交互 。
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int g_int = 123;static g_static_int2 = 456;static g_static_int_not_init;int main(void){int l_int = 3;int l_int2 = 4;static l_static_int =6;static l_static_int2;int * pint = (int*)malloc(sizeof(int));*pint = 12;printf("g_int:%d,tg_static_int2:%d tg_static_int_not_init:%d n",g_int,g_static_int2,g_static_int_not_init);printf("g_int:%p,tg_static_int2:%p tg_static_int_not_init:%p n",&g_int,&g_static_int2,&g_static_int_not_init);printf("l_int:%d tl_int2:%d tl_static_int:%d,tl_static_int2:%d,tpint:%dn",l_int,l_int2,l_static_int,l_static_int2,*pint);printf("l_int:%p tl_int2:%p tl_static_int:%p,tl_static_int2:%p,tpint:%pn",&l_int,&l_int2,&l_static_int,&l_static_int2,pint);while(1) {sleep(3);printf("PID:%dn",getpid());}free(pint);return 0;}
多次运行可以发现我们变量的地址在其应该对应的空间内,同时发现每次堆和stack的地址是每次不同的,这也是为了安全期间,设置的随机偏移 。顺便说下stack为主线程的栈,最大的大小默认是ulimit -s,一般为8MB,pthread_create 创建的栈大小一般为2MB,不同架构不同而且和ulimit 设置的大小有关,也可以自行更改 。
三 计算程序内存大小至于程序内存使用大小,比较简单的方法是top -p pid 直接看到如下:
推荐阅读
- linux系统下访问ftp服务器出现中文乱码怎么处理?
- linux系统安装mysql提示初始化失败怎么处理?
- JAVA中计算两个日期时间的差值竟然也有这么多门道
- linux系统下禁止上传目录执行php脚本?
- Linux 压缩命令
- 跳表在Java中的实现
- 生活小窍门美白
- 大学生|丈母娘中意的“女婿职业”排名,榜首意料之中,公务员没进前3
- 中成药|辅警夏季招聘正式开启,面向3类人优先招录,有五险一金!
- 央行|上半年住户存款创近年同期新高 为啥中国人更爱存钱了?专家释疑