用户程序使用malloc申请的内存空间在什么范围_内存空间之栈与堆

No.1

进程的地址空间

现代的操作系统为应用程序提供了一个虚拟的内存空间。在32位的系统里,这个内存空间拥有4GB的寻址能力,Linux默认情况下将高地址的1GB空间分配给内核,用户使用剩下的3GB的内存空间称为“用户空间”,一般来讲,应用程序使用的内存空间有如下的“默认权限”:

  • :栈用于维护函数系统调用的上下文,离开了栈,函数调用就没法实现。

  • :堆是用来容纳应用程序动态分配的内存区域,当程序使用malloc或new分配内存时,得到的内存来自堆里。

  • 可执行文件映像:这里存储着可执行文件在内存里的映像,由装载器在装载时将可执行文件的内存读取或映射在这里。

  • 保留区:保留区并不是一个单一的内存区域,而是对内存中受到保护而禁止访问的内存区域的总称。例如:大多数操作系统里,极小的地址通常都是不允许访问的:如NULL。通常C语言将无效的指针赋值为0也是出于这个考虑。

No.2

栈在程序运行中具有举足轻重的位置,栈保存了一个函数调用所需要的维护信息,这常常被称为堆栈帧或活动记录。堆栈帧一般包括如下几方面内容:

  • 函数的返回地址和参数。

  • 临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。

  • 保存的上下文:包括在函数调用前后需要保持不变的寄存器。

71cbc2bef41fc31d28fab024cacdbc6b.png

在i386中,一个函数的活动记录用ebp和esp这两个寄存器划定范围。esp寄存器始终指向栈的顶部,同时也指向了当前函数的活动记录的顶部。而相对的,ebp寄存器指向了函数活动记录的一个固定位置,ebp寄存器又被称为帧指针。ebp所直接指向的数据是调用该函数前ebp的值,这样在函数返回的时候,可以读取ebp的值,通过读取这个值恢复到调用前的值。一个i386下的函数总是这样调用的:

  • 把所有或一部分参数压入栈中,如果没有其他参数入栈,那么就使用某些特定的寄存器传值。

  • 把当前指令的下一条指令的地址压入栈中。

  • 跳转到函数体执行。

No.3

堆是一块巨大的空间,常常占据整个虚拟空间的绝大部分。在这片空间里,程序可以请求一块连续内存,并自由的使用,这块内存在程序主动放弃之前一直保持有效。

No.4

malloc()相关问题

malloc()申请的内存,进程结束以后还会不会存在?

  • 当进程结束以后,所有与操作系统相关的资源,包括进程的地址空间、物理内存、打开的文件、网络链接等都被操作系统关闭或回收,所以无论malloc()申请了多少内存,进程结束以后都不存在了。

malloc()的空间是不是连续的?

  • 如果“空间”是指虚拟空间的话,那么答案是连续的,即每一次malloc()分配后返回的空间都可以看做是一块连续的地址。如果空间是指“物理空间”的话,则答案是不一定连续,因为一块连续的虚拟地址空间有可能是若干个不连续的物理页映射而成。

文章转自:小组18级成员--刘婷

bceb129f421e4623c7115cb0fd039090.png


版权声明:本文为weixin_35101697原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。