C程序内存布局

作为计算机专业的来说,程序入门基本都是从C语言开始的,了解C程序中的内存布局,对我们了解整个程序运行,分析程序出错原因,会起到事半功倍的作用 。
C程序的内存布局包含五个段,分别是STACK(栈段),HEAP(堆段),BSS(以符号开头的块),DS(数据段)和TEXT(文本段)。
每个段都有自己的读取,写入和可执行权限。如果程序尝试以不允许的方式访问内存,则会发生段错误,也就是我们常说的coredump。
段错误是导致程序崩溃的常见问题。核心文件(核心转储文件)也与段错误相关联,开发人员使用该文件来查找崩溃的根本原因(段错误)。
下面我们将深入这五个段,更加详细的讲解每个段在程序开发或者运行中的作用。
High Addresses ---> .----------------------.
| Environment |
|----------------------|
| | Functions and variable are declared
| STACK | on the stack.
base pointer -> | - - - - - - - - - - -|
| | |
| v |
: :
. . The stack grows down into unused space
. Empty . while the heap grows up.
. .
. . (other memory maps do occur here, such
. . as dynamic libraries, and different memory
: : allocate)
| ^ |
| | |
brk point -> | - - - - - - - - - - -| Dynamic memory is declared on the heap
| HEAP |
| |
|----------------------|
| BSS | Uninitialized data (BSS)
|----------------------|
| Data | Initialized data (DS)
|----------------------|
| Text | Binary code
Low Addresses ----> '----------------------'
栈
- 它位于较高的地址,与堆段的增长和收缩方向正好相反。
- 函数的局部变量存在于栈上
- 调用函数时,将在栈中创建一个栈帧。
- 每个函数都有一个栈帧。
- 栈帧包含函数的局部变量参数和返回值。
- 栈包含一个LIFO结构。函数变量在调用时被压入栈,返回时将函数变量从栈弹出。
- SP(栈指针)寄存器跟踪栈的顶部。
#include
int main(void) {
int data; // 局部变量,存储在栈上
return 0;
}
堆
- 用于在运行时分配内存。
- 由内存管理函数(如malloc、calloc、free等)管理的堆区域,这些函数可以在内部使用brk和sbrk系统调用来调整其大小。
- 堆区域由进程中的所有共享库和动态加载的模块共享。
- 它在堆栈的相反方向上增长和收缩。
#include
int main(void) {
char *pStr = malloc(sizeof(char)*4); //pStr指向堆地址
return 0;
}
BSS(未初始化的数据块)
- 包含所有未初始化的全局和静态变量。
- 此段中的所有变量都由零或者空指针初始化。
- 程序加载器在加载程序时为BSS节分配内存。
#include
int data1; // 未初始化的全局变量存储在BSS段
int main(void) {
static int data2; // 未初始化的静态变量存储在BSS段
return 0;
}
DS(初始化的数据块)
- 包含显式初始化的全局变量和静态变量。
- 此段的大小由程序源代码中值的大小决定,在运行时不会更改。
- 它具有读写权限,因此可以在运行时更改此段的变量值。
- 该段可进一步分为初始化只读区和初始化读写区。
#include
int data1 = 10 ; //初始化的全局变量存储在DS段
int main(void) {
static int data2 = 3; //初始化的静态变量存储在DS段
return 0;
}
TEXT
- 该段包含已编译程序的二进制文件。
- 该段是一个只读段,用于防止程序被意外修改。
- 该段是可共享的,因此对于文本编辑器等频繁执行的程序,内存中只需要一个副本。
深入
现在有一个简单的程序,代码如下:
#include
int main(void) {
return 0;
}
我们通过如下命令进行编译
gcc -g a.cc -o a
然后通过size命令,可以看到各个段的大小
[root@build src]# gcc a.c -o a
[root@build src]# size a
text data bss dec hex filename
1040 484 16 1540 604 a
其中前三列分别为可执行程序a的text、data以及bss段的大小,第四列为该三段大小之和,第四列为该大小的十六进制表示,最后一列是文件名。
增加一个未初始化的静态变量
#include
int main(void) {
static int data;
return 0;
}
通过size命令
[root@build src]# size a
text data bss dec hex filename
1040 484 24 1548 60c a
从上面可以看出,bss段size变大
增加一个初始化的静态变量
#include
int main(void) {
static int data = 10;
return 0;
}
通过size命令
[root@build src]# size a
text data bss dec hex filename
1040 488 16 1544 608 a
从上面可以看出,data段size变大
增加一个未初始化的全局变量
#include
int data;
int main(void) {
return 0;
}
通过size命令
[root@build src]# size a
text data bss dec hex filename
1040 484 24 1548 60c a
从上面可以看出,bss段size变大
数据段的只读区域和读写区域
#include
char str[]= "Hello world";
int main(void) {
printf("%s\n",str);
str[0]='K';
printf("%s\n",str);
return 0;
}
输出
Hello world
Kello world
可以看到上面的示例str是一个全局数组,因此它将进入数据段。 还可以看到能够更改该值,因此它具有读取和写入权限。
现在查看其他示例代码
#include
char *str= "Hello world";
int main(void) {
str[0]='K';
printf("%s\n",str);
return 0;
}
在上面的示例中,我们无法更改数组字符是因为它是文字字符串。常量字符串不仅会出现在数据部分,而且所有类型的const全局数据都将进入该部分。
数据块只读部分,通常除了const变量和常量字符串外,程序的文本部分(通常是.rodata段)也存在于数据块的只读部分,因为通常无法通过程序进行修改。
C程序内存布局的更多相关文章
- C语言程序内存布局
C语言程序内存布局 如有转载,请注明出处:http://blog.csdn.net/embedded_sky/article/details/44457453 作者:super_bert@csdn 一 ...
- 一起talk C栗子吧(第一百三十一回:C语言实例--C程序内存布局三)
各位看官们,大家好.上一回中咱们说的是C程序内存布局的样例,这一回咱们继续说该样例.闲话休提,言归正转.让我们一起talk C栗子吧. 看官们,关于C程序内存布局的样例,我们在前面的两个章回都介绍过了 ...
- 用一个词(TASPK)牢记C程序内存布局
一个典型的C程序内存布局,从低地址到高地址分别为: 1. text (正文段,即代码段 Code Segment) 2. data (已经初始化的数据段) 3. bss (未被初始化的数据段 Bloc ...
- C++程序内存布局
代码区(code area) 程序内存空间 全局数据区(data area) 堆区(heap area) 栈区(stack area) 一个由C/C++编译的程序占用的内存分为以下几个部分, 1) ...
- linux C 程序内存布局
参考: 1. http://www.cnblogs.com/clover-toeic/p/3754433.html 2. http://www.cnblogs.com/jacksu-tencent/p ...
- ESP32应用程序的内存布局
应用程序内存布局 ESP32芯片具有灵活的内存映射功能.本节介绍ESP-IDF在默认情况下如何使用这些功能. ESP-IDF中的应用程序代码可以放置在以下内存区域之一中. IRAM(指令RAM) ES ...
- c++内存布局与c程序的内存布局
c/c++的内存布局:堆,栈,自由存储区(与堆的区别),全局/静态存储区,常量存储区(字符串常量,const常量) http://www.cnblogs.com/QG-whz/p/5060894.ht ...
- UNIX高级环境编程(8)进程环境(Process Environment)- 进程的启动和退出、内存布局、环境变量列表
在学习进程控制相关知识之前,我们需要了解一个单进程的运行环境. 本章我们将了解一下的内容: 程序运行时,main函数是如何被调用的: 命令行参数是如何被传入到程序中的: 一个典型的内存布局是怎样的: ...
- 探讨C++ 变量生命周期、栈分配方式、类内存布局、Debug和Release程序的区别
探讨C++ 变量生命周期.栈分配方式.类内存布局.Debug和Release程序的区别(一) 今天看博客园的文章,发现博问栏目中有一个网友的问题挺有趣的,就点进去看了下,标题是“C++生存期问题”,给 ...
随机推荐
- golang web源码解析
Go的web工作原理 在Go中使用及其简单的代码即可开启一个web服务.如下: //开启web服务 func test(){ http.HandleFunc("/", sayHel ...
- 哲学家就餐问题-Java语言实现死锁避免
哲学家就餐问题-Java语言实现死锁避免 我死锁预防是至少破坏死锁产生的四个必要条件之一,带来的问题就是系统资源利用率低且不符合开发习惯,而死锁避免不是事先釆取某种限制措施破坏死锁的必要条件,只是注意 ...
- Android系统编程入门系列之应用内数据保存数据库
上篇文章已经介绍了如何使用SharedPreferences存储键值对形式的轻量级数据,对于那些相同结构的多组数据,类似于存储Java中定义的类的多个对象属性值,如果按照键值对的形式一条条读写,需要分 ...
- Linux - last 命令(Mac 电脑)
前言 为啥写这篇? 因为听 grep.sed 教程的时候有这个命令栗子 加上工作中,运维给我排查问题的时候也用到了,感觉挺重要,先了解为敬! 命令作用 显示用户和TTY的最后登录次数 这个是在 Mac ...
- Mybatis-Plus常用的查询方法--看这一篇就够了!!!
前言: Mybatis-Plus作为Mybatis的增强,自己封装了很多简单还用的方法,来解脱自己写sql! 对于项目的搭建小编就不在说了,可以参考: SpringBoot+Mybatis-Plus的 ...
- HearthbuddyHelper已经开源
https://github.com/V-arc/HearthbuddyHelper 只是为了稳定,没耗时多久写的一个中控,只是在逐渐堆加,并未进行重构. 通过写这个感受到自己对异步和wpf的理解还有 ...
- CodeForce-734C Anton and Making Potions(贪心+二分)
CodeForce-734C Anton and Making Potions C. Anton and Making Potions time limit per test 4 seconds m ...
- C# lambda 实现 Ascii 排序
var dir = new Dictionary<string, string>(); dir.Add("channelId", "1& ...
- AD学习笔记(基础)
AD学习 1 学习思路 1.1 学什么 1.2 怎么学 2 AD本身 3 AD project 3.1 任务层级 3.2 PCB流程 4 原理图工作环境设置 5 开始 5.1工程创建 5.2 元件库介 ...
- Charles抓包工具断点修改返回内容
在测试过程中,往往需要让服务器返回指定的内容,测试一些特殊情况.例如列表内容为空.数据异常的情况等.如果通过操作服务器配合构造相应的数据会比较麻烦,甚至不好构造数据.此时,可以使用Charles的断点 ...