[转帖] Linux 下面栈空间大小的实验

比如局部变量是保存在栈空间中的,今天突然在想栈的上限是多大呢,什么时候才会栈溢出?

ulimit 命令

linux下使用ulimit 命令可以查看系统的很多上限值。

  • ulimit -a 查看所有

这里写图片描述

  • ulimit -s 查看栈空间的大小

这里写图片描述

可以看到系统设置栈的上限是8M

测试

现在我们写个程序测试一下

两种方法:

1、第一种方法:最简单的是在函数或直接在main()函数里定义多个局部变量。

这里写图片描述

局部变量一定要初始化,不然可能不会给分配内存

2、第二种方法:使用递归申请栈空间更合适,测试方便。

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

int   i = 1;  //记录申请的次数 void func() { char a[1048576]; //一次申请 1 M 便于计算 printf("NO.%d %ld 字节 %p\n",i,sizeof(a),a); i++; func(); } main() { func(); }

这里写图片描述

共申请了7M ,第8次申请失败,因为栈里面还保存着其他数据,如main函数的参数,所以第8次申请不足1M,说明运行结果和ulimit查看的信息吻合。

3、物理内存有4G,那栈空间可以申请4G么?

设置栈的上限为4G

这里写图片描述

再次运行程序: 
这里写图片描述

竟然真的申请了4G,这时候就想到了虚拟内存机制和linux交换空间。显然,这4G真的要物理内存给提供那是不够的,因为除了我们申请的4G ,还有其他进程,内核也需要内存空间,所以肯定使用了交换空间,物理内存不够的时候,把暂时不用的内存数据临时保存到了交换空间。我的交换空间分配了2G 。 
申请成功了,但是明显感觉到了系统卡顿,有时侯在申请了接近3G 的时候会卡一下,此时应该是因为物理内存压力太大,正在往交换空间置换数据吧,然后剩下1G 申请完成。

4、冲动了!这次我们设置栈的上限为 7G > 4G物理内存+2G swap

这里写图片描述

运行: 
这里写图片描述

成功了。特别卡,第一次直接系统死机了。

但是有点不解了,物理内存+交换空间 = 6G , 为何能申请7G ? 但是有时候又会中途失败,不能分配7G。

5、寻址空间

需不需要担心申请内存过多,比如像上面递归定义了超多字符串,那地址够用么,变量太多,首地址会不会重复呢?

这个不必担心,64位系统CPU的寻址空间是 2^64 , 0 ~ 0xffffffffffffffff 系统根本用不完这么大的地址空间。况且我们个人电脑的物理内存才是仅仅4G。

所以,64位系统会有很大一部分地址范围用不到,据说这个叫AMD64空洞

6、申请堆空间

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

int   i = 1;  //记录申请的次数 void func() { char a[1048576] = {'1'}; //一次申请 1 M 便于计算 char *p = NULL; p = (char*)malloc(1048576); printf("NO.%d %ld 字节 %p --><-- %p\n",i,sizeof(a),a,p); i++; func(); } main() { func(); }

这里写图片描述


这里有个问题:经多次测试,如果malloc动态申请的内存特别大时,如上图,依次分配的内存地址是递减的,好像不符合堆向上增长的特点。

7、32位环境测试

上面的代码以gcc -m32 编译运行


这里也有个问题:

堆内存地址开始是减小的:

这里写图片描述

减到足够小时又开始增大:

这里写图片描述

有时侯会出现,栈后面用到的地址空间是前面动态申请过的(并未释放) 

8、有时候ulimit -s 设置数值过大时会失败,还会导致之后设置任何数值都不会成功。注销重新设置就可以了

这里写图片描述


总之,还是不要随便更改系统设置的栈大小,不然就会出现上面遇到的几个问题。一般系统默认设置栈段为8M、4M、2M或1M。

猜你喜欢

转载自www.cnblogs.com/jinanxiaolaohu/p/9294101.html
今日推荐