本文已参与「新人创作礼」活动,一起开启掘金创作之路。
General
Basically, the memory layout of C program contains five segments these are the stack segment, heap segment, BSS (block started by symbol), DS (Data Segment) and text segment.
Each segment has own read, write and executable permission. If a program tries to access the memory in a way that is not allowed then segmentation fault occurs.
A segmentation fault is a common problem that causes programs to crash. A core file (core dumped file) also associated with a segmentation fault that is used by the developer to finding the root cause of the crashing (segmentation fault).
基本上,C程序的内存布局包含五个段,分别是堆栈段,堆段,BSS(以符号开头的块),DS(数据段)和文本段。
每个段都有自己的读取,写入和可执行权限。 如果程序尝试以不允许的方式访问内存,则会发生段错误。
段错误是导致程序崩溃的常见问题。 core文件(core dumped文件)也与分段错误相关联,开发人员使用该文件来查找崩溃的根本原因(分段错误)。
Below find the memory Layout of C Program
1. Stack-堆栈段
2. Heap-堆段
3. BSS (Uninitialized data segment)-以符号开头的块
4. DS (Initialized data segment)-数据段
5. Text-文本段
Stack:
-
It located at a higher address and grows and shrinks opposite to the heap segment.
-
The stack contains local variables from functions and related book-keeping data(i.e. the return address of funtion).
-
A stack frame will create in the stack when a function is called.
-
Each function has one stack frame.
-
Stack frames contain function’s local variables arguments and return value.
-
The stack contains a LIFO structure. Function variables are pushed onto the stack when called and functions variables are popped off the stack when return.
-
SP(stack pointer) register tracks the top of the stack.
-
它位于较高的地址,并且在堆段的对面进行增长和缩小。
-
堆栈包含来自函数的局部变量和相关的簿记数据(例如,函数返回地址等)。
-
调用函数时,将在堆栈中创建一个栈帧。
-
每个功能都有一个栈帧。
-
栈帧包含函数的局部变量参数和返回值。
-
堆栈包含一个LIFO结构。
-
函数变量在被调用时被压入堆栈,而函数变量在返回时从堆栈中弹出。
-
SP(堆栈指针)寄存器跟踪堆栈的顶部。
#include <stdio.h>
int main(void)
{
int data; //local variable stored in stack
return 0;
}
Heap:
-
It is used to allocate the memory at run time.
-
Heap area managed by the memory management functions like malloc, calloc, free, etc which may internally use the brk and sbrk system calls to adjust its size.
-
The Heap area is shared by all shared libraries and dynamically loaded modules in a process.
-
It grows and shrinks in the opposite direction of the stack.
-
它用于在运行时分配内存。
-
由内存管理功能(如malloc,calloc,free等)管理的堆区域可以在内部使用brk和sbrk系统调用来调整其大小。
-
堆区域由进程中的所有共享库和动态加载的模块共享。
-
它沿堆栈的相反方向增长和缩小。
#include <stdio.h>
int main(void)
{
char *pStr = malloc(sizeof(char)*4); //stored in heap
return 0;
}
BSS(Uninitialized data segment):
-
It contain all uninitialized global and static variable.
-
All variables in this segment initialized by the zero(0) and pointer with the null pointer.
-
The program loader allocates memory for the BSS section when it loads the program.
-
它包含所有未初始化的全局变量和静态变量。
-
该段中的所有变量均由零(0)和空的指针作为初始化。
-
程序加载器在加载程序时为BSS部分分配内存。
#include <stdio.h>
int data1; // Uninitialized global variable stored in BSS
int main(void)
{
static int data2; // Uninitialized static variable stored in BSS
return 0;
}
DS(Initialized data segment):
-
It contains the explicitly initialized global and static variables.
-
The size of this segment is determined by the size of the values in the program’s source code and does not change at run time.
-
It has read-write permission so the value of the variable of this segment can be changed at run time.
-
This segment can be further classified into an initialized read-only area and an initialized read-write area.
-
它包含显式初始化的全局变量和静态变量。
-
该段的大小取决于程序源代码中值的大小,并且在运行时不会更改。
-
它具有读写权限,因此可以在运行时更改此段的变量的值。
-
该段可以进一步分类为初始化的只读区域和初始化的读写区域。
#include <stdio.h>
int data1 = 10 ; //Initialized global variable stored in DS
int main(void)
{
static int data2 = 3; //Initialized static variable stored in DS
return 0;
}
Text:
-
The text segment contains a binary of the compiled program.
-
The text segment is a read-only segment that prevents a program from being accidentally modified.
-
It is sharable so that only a single copy needs to be in memory for frequently executed programs such as text editors etc.
-
文本段包含已编译程序的二进制文件。
-
文本段是只读段,可以防止程序被意外修改。
-
它是可共享的,因此对于频繁执行的程序(例如文本编辑器等),仅一个副本需要存储在内存中。
Note: The size command basically lists section sizes as well as total size for the input object file.
注意: size命令基本上列出了输入对象文件的section大小以及总大小。
Examples
Let‘s see few examples to understand the memory layout of the C program.
我们来看几个例子,以了解C程序的内存布局。
memory-layout.c
#include <stdio.h>
int main(void)
{
return 0;
}
$ gcc memory-layout.c -o memory-layout
$ size memory-layout
text data bss dec hex filename
960 248 8 1216 4c0 memory-layout
- Now add a static uninitialized variable and check the size.
- 现在添加一个静态的未初始化变量并检查大小。
memory-layout.c
#include <stdio.h>
int main(void)
{
static int data; // Stored in uninitialized area
return 0;
}
$ gcc memory-layout.c -o memory-layout
$ size memory-layout
text data bss dec hex filename
960 248 12 1216 4c0 memory-layout
You can see the size of the .bss has been increased.
您可以看到.bss的大小已增加。
- Now add the initialized static variable and check the size.
- 您可以看到.bss的大小已增加。
memory-layout.c
#include <stdio.h>
int main(void)
{
static int data =10; // Stored in initialized area
return 0;
}
$ gcc memory-layout.c -o memory-layout
$ size memory-layout
text data bss dec hex filename
960 252 8 1216 4c0 memory-layout
You can see the size of the data segment has been increased.
您可以看到数据段的大小已增加。
- Now add the global uninitialized variable and check the size.
- 现在添加全局未初始化的变量并检查大小。
memory-layout.c
#include <stdio.h>
int data; // Stored in uninitialized area
int main(void)
{
return 0;
}
$ gcc memory-layout.c -o memory-layout
$ size memory-layout
text data bss dec hex filename
960 248 12 1216 4c0 memory-layout
You can see the size of the .bss has been increased.
您可以看到.bss的大小已增加。
- Now add the global and static uninitialized variable and check the size.
- 现在添加全局和静态未初始化变量并检查大小。
memory-layout.c
#include <stdio.h>
int data1; //Stored in uninitialized area
int main(void)
{
static int data2; //Stored in uninitialized area
return 0;
}
$ gcc memory-layout.c -o memory-layout
$ size memory-layout
text data bss dec hex filename
960 248 16 1216 4c0 memory-layout
The size of .bss increases as per the uninitialized global and static variables.
.bss的大小根据未初始化的全局变量和静态变量而增加。
- Now add the global and static initialized variable and check the size.
- 现在添加全局和静态初始化变量并检查大小。
memory-layout.c
#include <stdio.h>
int data1 = 0; //Stored in uninitialized area
int main(void)
{
static int data2 = 0; //Stored in uninitialized area
return 0;
}
$ gcc memory-layout.c -o memory-layout
$ size memory-layout
text data bss dec hex filename
960 264 8 1216 4c0 memory-layout
The size of the data segment increases as per the initialized global and static variables.
数据段的大小根据初始化的全局变量和静态变量而增加。
In the data segment, I have said that the “data segment can be further classified into the two-part initialized read-only area and an initialized read-write area”. So let us see two C programs to understand this concept.
在数据段章节里,我已经说过“数据段可以进一步分为两部分初始化的只读区域和初始化的读写区域”。 因此,让我们看两个C程序来理解这个概念。
memory-layout.c
#include <stdio.h>
char str[]= "Deep Technology";
int main(void)
{
printf("%s\n",str);
str[0]='k';
printf("%s\n",str);
return 0;
}
Output:
输出:
Deep Technology`
Keep Technology`
You can see the above example str is a global array, so it will go in the data segment. You can also see that I am able to change the value so it has read and write permission.
您可以看到上面的示例str是一个全局数组,因此它将进入数据段。 您还可以看到我能够更改该值,因此它具有读取和写入权限。
Now see the other example code,
现在查看其他示例代码,
#include <stdio.h>
char *str= "Deep Technology";
int main(void)
{
str[0]='k';
printf("%s\n",str);
return 0;
}
In the above example, we are not able to change the array character is because it is a literal string. A constant string does not only go in the data section (read only) but all types of const global data go in that section.
在上面的示例中,我们不能更改数组字符是因为它是文字字符串。 常量字符串不仅会进入数据只读部分,而且所有类型的const全局数据都将进入该部分。
It is not necessarily that const global and constant string go in the data section. It can be also in the text section of the program (normally the .rodata segment), as it is normally not modifiable by a program.
不一定要在数据部分中使用const全局字符串和常量字符串。 它也可以在程序的文本部分(通常是.rodata段)中,因为通常无法通过程序进行修改。