C语言程序内存布局

如有转载,请注明出处:http://blog.csdn.net/embedded_sky/article/details/44457453

作者:super_bert@csdn

一、几个概念

1.栈(Stack)

C语言通过栈来维护函数调用上下文,也就是说C中的函数、函数参数列表、局部变量、函数返回值都保存在栈内存中,在完成函数调用之后栈帧随即销毁,至于具体的压栈顺序和上下文维护工作由谁来完成,则取决于函数的调用方式(cdecl/stdcall/fastcall/pascal).

关于C函数调用约定,或者叫调用惯例(Calling Convention),以下表格中,个人认为出栈方应该叫做栈的维护方更确切,表格:

详细请看这里

栈帧一般包括如下几方面内容:

①函数的参数列表和返回值(返回地址);

②临时变量:包括非静态局部变量和编译器自动生成的其他临时变量;

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

栈增长示意图

2.堆(Heap)

堆空间是需要程序自行申请的,简言之 在C语言程序中对空间由malloc函数族(malloc/alloc/calloc/realloc)申请,当然在C++中还有new关键字。堆空间由程序猿自行申请,也需由程序猿自行释放(此处,Javaer们笑看你们打脸)。malloc/free  new/delete分别对应申请和释放内存,new/delete是C++中的关键字,不是函数。

通常情况下比较好的做法是,free掉之后,立即将指针置为NULL,因为通常if语句只会去判断指针是否为NULL(0x00000000),堆空间(内存)在free掉之后,该指针并不会指向NULL,也就是说free掉的是内存而不是指针,如果程序之后又用到该指针,后果将是不可预知的。如果被置为NULL,则可以被if语句检测出来,防止自己给自己留坑,C中的坑已经够多的了。

glibc中的malloc函数是这样处理用户堆空间请求的:

①对于小于128KB的请求,在现有的堆空间里,按照分配算法为他分配一块空间并返回;

②对于大于128KB的请求,malloc内部会调用mmap()函数分配一块匿名空间,然后在这块匿名空间中为用户分配空间。

mmap函数的具体用法请参考Linux  manpage,Windows环境下是没有mmap函数的,malloc函数族应该是依赖于 VirtualAlloc()函数申请堆空间。

3.动态链接库(Dynamic Libraries)

Linux/Unix环境下应该是***.so之类的文件,Windows下则是DLL(Dynamic Linking Libraries)。

二、Linux进程地址空间

先上图,箭头代表stack和heap的增长方向,dynamic libraries在2.4和2.6以后的内核中装载位置不一样,分别为0x40000000,0xBFXXXXXX.

Linux采用了分页的内存管理机制。由于x86体系的分页机制是基于分段机制的,因此,为了使用分页机制,分段机制是无法避免的。为了降低复杂性,Linux内核将所有段的基址都设为0,段限长设为4G,只是在段类型和段访问权限上有所区分,并且Linux内核和所有进程共享1个GDT,不使用LDT(即系统中所有的段描述符都保存在同一个GDT中),这是为了应付CPU的分段机制所能做的最少工作。

Linux内存管理机制可以分为3个层次,从下而上依次为物理内存的管理、页表的管理、虚拟内存的管理。

三、Windows进程地址空间

相较Linux而言,Windows环境下的进程空间布局就显得"支离破碎",

各位看官么看完这图估计会有点奇怪,一开始我也奇怪,为啥会有那么多stack呢?上面有说到,栈用于维护函数调用上下文,一个进程中调用函数所需存储的参数/变量/返回值,哪用得了那么多栈内存。

造成需要这么多栈内存的原因如下,每个线程的栈空间都是独立的,而Windows程序一般都是多线程,很大一部分原因Windows的进程耗费资源太大,线程优化得比*nix要好得多。试想一下,若在一个进程中通过CreateThread创建了多个线程,然后每个线程的栈空间都是独立的,且可以通过CreateThread API的参数来指定(系统默认的每个线程栈大小为1M byte),所以一旦程序起起来,内存空间已经支离破碎了。

然而我们的应用程序得在这个支离破碎的内存空间中去malloc堆(heap)空间,VirtualAlloc().

malloc函数族在Windows环境下最终依赖于VirtualAlloc()函数实现,而VirtualAlloc()函数像操作系统申请的空间必须是页大小的整数倍,也就是说对于x86系统一次性申请的heap最少是4096个byte,OS就是这么定的。但是OS还提供了一个堆管理器,堆管理器每次向OS申请一大片heap空间,然后在申请到的空间里给应用程序进行malloc。

HeapCreate创建一个堆;

HeapAlloc从堆空间中申请内存;

HeapFree释放内存;

HeapDestroy销毁一个堆;

相当于咱们从冷库里一次性批发了一箱冰激凌放在家里,咱们想吃的时候就一个一个去冰箱拿,想吃几个就拿几个。

此文只是抛砖引玉,其中很多地方都值得深入去研究、理解。

参考:http://www.cnblogs.com/zszmhd/archive/2012/08/29/2661461.html

x64系统程序内存布局请参考:http://blog.chinaunix.net/uid-27119491-id-3325943.html

C语言程序内存布局的更多相关文章

  1. 一起talk C栗子吧(第一百三十一回:C语言实例--C程序内存布局三)

    各位看官们,大家好.上一回中咱们说的是C程序内存布局的样例,这一回咱们继续说该样例.闲话休提,言归正转.让我们一起talk C栗子吧. 看官们,关于C程序内存布局的样例,我们在前面的两个章回都介绍过了 ...

  2. C语言程序内存的分区

    本文转载自:https://blog.csdn.net/shulianghan/article/details/20472269 C语言程序内存分配 (1) 内存分区状况 栈区 (stack) :  ...

  3. 用一个词(TASPK)牢记C程序内存布局

    一个典型的C程序内存布局,从低地址到高地址分别为: 1. text (正文段,即代码段 Code Segment) 2. data (已经初始化的数据段) 3. bss (未被初始化的数据段 Bloc ...

  4. C程序内存布局

    作为计算机专业的来说,程序入门基本都是从C语言开始的,了解C程序中的内存布局,对我们了解整个程序运行,分析程序出错原因,会起到事半功倍的作用 . C程序的内存布局包含五个段,分别是STACK(栈段), ...

  5. C++程序内存布局

      代码区(code area) 程序内存空间 全局数据区(data area) 堆区(heap area) 栈区(stack area) 一个由C/C++编译的程序占用的内存分为以下几个部分, 1) ...

  6. C语言程序内存分布

     一个进程的数据在内存中的布局如下图: bss段(bss segment):可读可写不可执行,通常用来存放程序中未初始化的全局变量.bss是英文Block Started by Symbol的简称.b ...

  7. linux C 程序内存布局

    参考: 1. http://www.cnblogs.com/clover-toeic/p/3754433.html 2. http://www.cnblogs.com/jacksu-tencent/p ...

  8. ESP32应用程序的内存布局

    应用程序内存布局 ESP32芯片具有灵活的内存映射功能.本节介绍ESP-IDF在默认情况下如何使用这些功能. ESP-IDF中的应用程序代码可以放置在以下内存区域之一中. IRAM(指令RAM) ES ...

  9. c++内存布局与c程序的内存布局

    c/c++的内存布局:堆,栈,自由存储区(与堆的区别),全局/静态存储区,常量存储区(字符串常量,const常量) http://www.cnblogs.com/QG-whz/p/5060894.ht ...

随机推荐

  1. Git仓库创建和文件提交

    参考质料:廖雪峰的个人网站 Git 什么是Git:一个分布式版本管理系统: 作用:管理你的历史文件,文件修改历史,团队协作. Windows下安装Git: 到链接下载安装包,国内镜像 云盘 安装完成后 ...

  2. MySql Jar 包下载

    MySql JAR 包下载 我们要使用Spring 链接MySql  需要两个Jar 包   一个是C3p0   一个是MySql 的Connection Jar  包 C3p0: 进入下面的网址 h ...

  3. Pycharm中如何加载多个项目?

    今天在使用Pycharm工具练习Python时遇到一个疑问:在已存有项目A工程的前提下如何新建另一个项目B,且两者并存? 基本操作步骤: 在File下拉项中选择"New Project&qu ...

  4. CentOSv6.8 修改防火墙配置、修改SSH端口

    查看防火墙目前使用状况: service iptables status 修改防火墙配置: vi /etc/sysconfig/iptables 重启防火墙,让刚才修改的配置生效: service i ...

  5. Coin Change (II)(完全背包)

                                                               Coin Change (II) Time Limit: 1000MS   Mem ...

  6. bzoj1968 COMMON 约数研究

    Input只有一行一个整数 N(0 < N < 1000000).Output只有一行输出,为整数M,即f(1)到f(N)的累加和.Sample Input 3 Sample Output ...

  7. 使用python实现后台系统的JWT认证(转)

    今天的文章介绍一种适用于restful+json的API认证方法,这个方法是基于jwt,并且加入了一些从oauth2.0借鉴的改良. 1. 常见的几种实现认证的方法 首先要明白,认证和鉴权是不同的.认 ...

  8. 无向图广度优先遍历及其matlab实现

    广度优先遍历(breadth-first traverse,bfts),称作广度优先搜索(breath first search)是连通图的一种遍历策略.之所以称作广度优先遍历是因为他的思想是从一个顶 ...

  9. Python学习手册 :Python 学习笔记第一天

    获取当前目录路径: import os os.getcwd() 在输入python程序时,尽量让不是嵌套结构的语句处于最左侧,要不然系统或许会出现"SyntaxError"错误 获 ...

  10. 苹果 AR 新专利马上登陆 Facetime|Facebook 要用 VR 玩直播

    附上VR技术福利视频 链接: https://pan.baidu.com/s/1boGGVs7 密码: viy8 点击关注有更多VR技术资源哦 苹果 AR 新专利马上登陆 Facetime ,使用光场 ...