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++生存期问题”,给 ...
随机推荐
- uni-app 入门小白纯徒手编写组件 hello-popup
我的需求是:弹出框顶部有 title,底部有确认和取消按钮.这两部分固定,中间部分 content 的高度随自身内容会动态增长,但是它最大高度不能超过父节点 bg 的 80%,而父节点 bg 的高度也 ...
- 【HMS Core 6.0全球上线】Network Kit全链路网络加速技术,应用无惧网络拥塞
HMS Core 6.0已于7月15日全球上线,本次版本向广大开发者开放了众多全新能力与技术.其中HMS Core Network Kit开放了全链路网络加速技术,助力开发者为用户提供低时延的畅快网络 ...
- 代码保留格式(高亮)复制到Word(转载)
将代码保持高亮复制粘贴到word上,一些方法如下: 方法一:借助网站http://www.planetb.ca/syntax-highlight-word/(代码有编号,整体排版精美令人舒适,但语言有 ...
- Ordering the Soldiers 题解
CodeChef:ORDERS 简化题意: \(n\) 个人排队,给定每个人需要向左移动几个,求最终排列. 即还原逆序对. 错误想法 既然知道每个人向左移动 \(a_i\) 个,那就相当于让他的排名 ...
- WPF 通过进程实现异常隔离的客户端
当 WPF 客户端需要实现插件系统的时候,一般可以基于容器或者进程来实现.如果需要对外部插件实现异常隔离,那么只能使用子进程来加载插件,这样插件如果抛出异常,也不会影响到主进程.WPF 元素无法跨进程 ...
- 解析Markdown文件生成React组件文档
前言 最近做的项目使用了微前端框架single-spa. 对于这类微前端框架而言,通常有个utility应用,也就是公共应用,里面是各个子应用之间可以共用的一些公共组件或者方法. 对于一个团队而言,项 ...
- 使用IntelliJ工具打包kotlin为bat文件运行报错 Exception in thread "main" java.lang.NoClassDefFoundError
Exception in thread "main" java.lang.NoClassDefFoundError 这个很有可能是因为idea里的java版本与电脑上的java环境 ...
- Shell系列(24)- 条件判断之文件类型
按照文件类型进行判断 标红,记住:其他了解即可 测试选项 作用 -b 文件 判断该文件是否存在,并且是否为块设备文件(是块设备文件为真) -c 文件 判断该文件是否存在,并且是否为字符设备文件(是字符 ...
- 如何在Ubuntu 18.04安装Git
在Ubuntu 18.04安装Git 更新apt包列表 apt-get update -y apt-get upgrade -y 安装Git: apt install git 检查Git版本 git ...
- jquery-ui dialog, ajax FormData [snippet], $.ajax setRequestHeader
html: <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery- ...