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. js如何获取客户端IP

    1.在HTML页面里面引入<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script> 2.获取 ...

  2. LuoguP1196_银河英雄传说_KEY

    银河英雄传说 题目描述 公元5801年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历799年,银河系的两大军事集团在巴米利恩星域爆 ...

  3. 自定义工作流活动报错:您无法登陆系统。原因可能是您的用户记录或您所属的业务部门在Microsoft Dynamics 365中已被禁用。

    本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复265或者20170926可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me ...

  4. 深入理解计算机系统chapter3

    栈在处理过程调用中起到至关重要的作用,栈向下增长,栈顶元素的地址是所有栈中元素最小的.栈指针%esp保存着栈顶元素的地址 控制: 重点: 基于条件数据传送的代码比基于条件控制转移(预测错误惩罚比较高) ...

  5. 二、js的控制语句

    二.流程控制语句 ECMA-262规定了一组流程控制语句.语句定义了ECMAScript中的主要语法,语句通常由一个或者多个关键字来完成给定的任务.诸如:判断.循环.退出等.   语句的定义   在E ...

  6. 51nod 1451 合法三角形 判斜率去重,时间复杂度O(n^2)

    题目: 这题我WA了3次,那3次是用向量求角度去重算的,不知道错在哪了,不得不换思路. 第4次用斜率去重一次就过了. 注意:n定义成long long,不然求C(3,n)时会溢出. 代码: #incl ...

  7. Struts201---环境搭配

    开发工具:Eclipse   Struts版本:2.3.24 最近在学SSH框架,SSH是 struts+spring+hibernate的一个集成框架,是目前比较流行的一种Web应用程序开源框架.集 ...

  8. samba的安装和配置

    samba是Linux系统上的一种文件共享协议,可以实现Windows系统访问Linux系统上的共享资源,现在介绍一下如何在Ubuntu 14.04上安装和配置samba 实验环境 Ubuntu 14 ...

  9. ConvertUtils.register注册转换器

    当用到BeanUtils的populate.copyProperties方法或者getProperty,setProperty方法其实都会调用convert进行转换 但Converter只支持一些基本 ...

  10. java web jsp原理图 ,静态包含,动态包含,out与response.getWrite()

    jsp原理图 ,静态包含,动态包含,out与response.getWrite()