堆(heap)和栈(stack)是进程中的两片内存区域,这是学习编程过程中,特别是C语言这种直接操作内存的程序员必须要掌握的知识。如果能直观的看到进程运行时堆内存和栈内存的变化,相信对内存知识的掌握和程序的调试都能带来帮助。
OnTheSSH是一款SSH工具,提供了图形化的进程内存的监控功能,今天我们就使用它来分析栈和堆内存。
1、先分析栈内存
在linux中,栈内存大小一般限制在8M,可以用 ulimit -a 命令查看系统对栈内存的限制:
编写一段C程序来测试栈内存的申请:
// test1.c #include <stdio.h> main() { // 4M栈内存 char cache[1024 * 1024 * 4]; printf("%X", &cache); //这里scanf()用来阻止程序退出 int a = 0; scanf("%d", &a); }
cache变量是char类型数组,长度定义为4M(1024 * 1024 * 4),然后编译、运行:
程序打印出cache变量的地址: FFA15EA0,先记录在这里,一会儿和进程内存栈地址进行比较。
打开 OnTheSSH 软件的进程监控功能,在进程列表中找到a.out进程,然后点击顶部的“进程内存”按钮:
在进程内存窗口中(下图),显示了a.out进程(进程id 18622)的内存实时状态,上半部分是内存页角度的状态,下半部分是进程在内存中的布局和映射。
内存映射图中显示,a.out进程的栈内存段大小是4M,和cache变量大小相符,地址范围7fffffa15000-7fffffe17000,程序打印的cache地址是FFA15EA0,去除地址前缀,cache地址正好落在栈地址范围内:
2、接下来分析堆内存
C语言中堆内存要用malloc来申请,在64位系统中几乎可以申请到你想得到的任意内存大小(上限极大),比如下面的代码:
//test2.c #include <stdio.h> #include <malloc.h> #include <string.h> main() { int len = 1024 * 1024 * 1024; //申请1G堆内存 int *p = (int*)malloc(len); printf("%X", p); int a = 0; scanf("%d", &a); }
通过malloc申请了1G内存,然后编译、运行:
再次查看OnTheSSH的内存映射:
比对内存地址,malloc申请到的内存地址正落在这段范围:
内存映射也“真实”反应申请到了1G内存,但情况确实如此吗,不尽然!我们用 OnTheSSH 的系统监控功能查看一下内存在系统层面的使用情况:
可以看到系统层面只使用了0.51G内存,肯定没有计算a.out进程的内存啊!怎么回事?
其实这里就碰到了Linux中的copy on write机制:进程中申请的内存在没有写入时,它只是声明存在,系统并不分配物理内存,直到这片内存被写入时才真正分配。
继续测试,修改代码,对malloc申请的堆内存进行写入操作:
//test3.c #include <stdio.h> #include <malloc.h> #include <string.h> main() { int len = 1024 * 1024 * 1024; //申请1G堆内存 int *p = (int*)malloc(len); //写内存 memset(p, 0, len); int a = 0; scanf("%d", &a); }
编译运行,再看系统内存监控,可以看到这时内存才真的被使用:
标签:1024,技巧,OnTheSSH,int,cache,内存,进程,include From: https://www.cnblogs.com/dyf029/p/17764711.html