美文网首页
C程序的内存布局

C程序的内存布局

作者: 天黑北风吹 | 来源:发表于2016-08-15 10:38 被阅读33次

学习了操作系统的一些基本知识之后,有必要对C程序的结构进行一下学习,事实上它并不是那么简单,这篇文章就对C语言程序在内存中的布局进行一下小结。

总述

一个典型的可执行的C语言程序在内存中应该有以下几部份组成:
(1)代码段
(2)初始化数据段(数据段)
(3)未初始化数据段(BSS段)
(4)栈
(5)堆

memorylayout.png
代码段

代码段中存放可执行的指令,在内存中,为了保证不会因为堆栈溢出被覆盖,将其放在了堆栈段下面(从上图可以看出)。通常来讲代码段是共享的,这样多次反复执行的指令只需要在内存中驻留一个副本即可,比如C编译器,文本编辑器等。代码段一般是只读的,程序执行时不能随意更改指令,也是为了进行隔离保护。

初始化数据段

初始化数据段有时就称之为数据段。数据段是一个程序虚拟地址空间的一部分,包括一全局变量和静态变量,这些变量在编程时就已经被初始化。数据段是可以修改的,不然程序运行时变量就无法改变了,这一点和代码段不同。

数据段可以细分为初始化只读区和初始化读写区。这一点和编程中的一些特殊变量吻合。比如全局变量int global = 1就被放在了初始化读写区,因为global是可以修改的。而const int flag = 2就会被放在只读区,很明显,flag是不能修改的。

未初始化数据段

未初始化数据段有时称之为BSS段,BSS是英文Block Started by Symbol的简称,BSS段属于静态内存分配。存放在这里的数据都由内核初始化为0。未初始化数据段从数据段的末尾开始,存放有全部的全局变量和静态变量并被,默认初始化为0,或者代码中没有显式初始化。比如static int i; 或者全局int j;都会被放到BSS段。

栈区和堆区一般相邻,但沿着相反方向增长。当栈指针和堆指针相等就说明堆栈内存耗尽。(现代大地址空间和虚拟内存技术可以将栈和堆放在任何地方,但是二者增长方向也是相反的)。栈区存放程序的栈,一种LIFO结构,一般都在内存的高地址段。在X86架构中栈地址是向0地址增长,其他一些架构中相反。栈指针寄存器记录栈顶地址,每次有值push进栈就会对栈指针进行修改。一个函数push进栈的一组值被称做堆栈帧,堆栈帧保存有返回地址的最小的返回地址。

栈中存放有自动变量和每次函数调用时的信息。每次函数调用返回地址,一些调用者环境信息(比如寄存器)都被存放在栈中。然后新调用的函数就在栈中为他们的自动或者临时变量分配内存空间,这就是C中递归函数调用的过程。每次递归函数调用自己,新的堆栈帧就被创建,这样新的变量集合就不会被其他函数实例的变量集合影响了。

堆是动态内存分配区,堆地址起始于BSS段末端,然后从这里向高地址增长。堆中内存分配管理由malloc,remalloc和free标准库函数来完成(这些库函数的实现原理后续会讨论)。堆可以被进程的所有共享库以及动态加载模块共享。

例子

用size命令来看代码的内存布局,下面看一个最简单的程序:

#include <stdio.h>

int main(int argc, char* argv[])
{
    printf("Hello world!\n");
    return 0;
}

下面编译并查看其分配内存大小

[root@node216 tmp]# gcc hello.c -o hello
[root@node216 tmp]# size hello
   text    data     bss     dec     hex filename
   1156     492      16    1664     680 hello

增加一个全局变量global不进行初始化:

#include <stdio.h>
int global;
int main(int argc, char* argv[])
{
    printf("Hello world!\n");
    return 0;
}

编译查看分配情况:

[root@node216 tmp]# gcc hello.c  -o hello
[root@node216 tmp]# size hello
   text    data     bss     dec     hex filename
   1156     492      24    1672     688 hello

现在对global初始化为1:

#include <stdio.h>
int global=1;
int main(int argc, char* argv[])
{
    printf("Hello world!\n");
    return 0;
}

再看段分配:

[root@node216 tmp]# gcc hello.c -o hello
[root@node216 tmp]# size hello
   text    data     bss     dec     hex filename
   1156     496      16    1668     684 hello

相关文章

  • Objective-C 引用计数的原理和内部实现

    背景 - 内存管理 Objective-C 建立在 C 语言的基础上。C 语言程序的内存布局主要包括: 栈:由编译...

  • C程序的内存布局

    学习了操作系统的一些基本知识之后,有必要对C程序的结构进行一下学习,事实上它并不是那么简单,这篇文章就对C语言程序...

  • C程序的内存布局

    一个典型的C程序内存表现组成应该有以下几个部分: 代码段/文本段(Text segment) 初始化数据段(Ini...

  • C语言的内存布局

    C语言编程程序的内存如何布局 C语言程序连接过程中的特性和常见错误 C语言程序的运行方式 一:C语言程序的存储区域...

  • iOS内存管理底层原理

    内存布局 了解程序内存布局请点击程序的内存布局以及栈、堆原理[https://www.jianshu.com/p/...

  • 必须知道的C语言知识细节:C程序编译后内存到底是如何布局

    C语言程序编译以后,代码和数据都必须存放在内存中由CPU执行。理解C程序内存是如何划分布局,才能真正理解C语言中变...

  • C/C++程序的内存布局

    referenceMemory Layout of C Programshttp://www.jianshu.co...

  • C语言程序内存布局

    C语言笔记之02-C语言程序内存布局 我们知道C语言的编译过程分为:预处理-编译-汇编-链接-生成可执行文件,而这...

  • C++程序的内存布局

    转载声明:http://blog.csdn.net/imyfriend/article/details/84971...

  • C语言-程序的内存布局

    0.前记自己对一些容易混淆的概念,知识点做了整理和摘记,并尝试用自己的话重新叙述和组织逻辑,加深理解,并方便之后查...

网友评论

      本文标题:C程序的内存布局

      本文链接:https://www.haomeiwen.com/subject/utrusttx.html