作为计算机专业的来说,程序入门基本都是从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 ----> '----------------------'
#include <stdio.h>
int main(void) {
int data; // 局部变量,存储在栈上
return 0;
}
#include <stdio.h>
int main(void) {
char *pStr = malloc(sizeof(char)*4); //pStr指向堆地址
return 0;
}
#include <stdio.h>
int data1; // 未初始化的全局变量存储在BSS段
int main(void) {
static int data2; // 未初始化的静态变量存储在BSS段
return 0;
}
#include <stdio.h>
int data1 = 10 ; //初始化的全局变量存储在DS段
int main(void) {
static int data2 = 3; //初始化的静态变量存储在DS段
return 0;
}
现在有一个简单的程序,代码如下:
#include <stdio.h>
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 <stdio.h>
int main(void) {
static int data;
return 0;
}
通过size命令
[root@build src]# size a
text data bss dec hex fi
从上面可以看出,bss段size变大
#include <stdio.h>
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 <stdio.h>
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 <stdio.h>
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 <stdio.h>
char *str= "Hello world";
int main(void) {
str[0]='K';
printf("%s\n",str);
return 0;
}
在上面的示例中,我们无法更改数组字符是因为它是文字字符串。常量字符串不仅会出现在数据部分,而且所有类型的const全局数据都将进入该部分。
数据块只读部分,通常除了const变量和常量字符串外,程序的文本部分(通常是.rodata段)也存在于数据块的只读部分,因为通常无法通过程序进行修改。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8