对于C语言的学习、掌握,内存的理解是一定绕不开的,本文主要是基于实际的小例子来简单讲解下C程序的内存分布
通常一个C程序主要由以下几个部分构成,
- 代码段(Text segment or Code segment)
- 已初始化数据段(Initialized data segment )
- 未初始化数据段也常称为"bss"段(Uninitialized data segment )
- 栈(Stack)
- 堆(Heap)
一探究竟
名词解释
-
代码段( Code segment )
代码段主要存储的是可执行程序的代码指令,从内存区域划分看,代码通常可以放在堆栈的下方,防止堆栈溢出导致代码段被覆盖.另外通常代码段是只读的,防止可执行程序对程序的指令造成修改.
-
已初始化数据段(Data Segment)
已初始化话数据段,通常简称为数据段. 包含了已经由程序员完成初始化的全局变量、静态变量.数据段可以进一步划分为,只读和可读可写两个区域.
例如,在C代码中,int test = 1; 定义在mian函数外(全局变量),就存放在可读可写区域.
然后定义的全局char指针变量, char *str = “Hello”, "Hello"就是被存储在只读区域. -
未初始化数据段(Uninitialized data segment )
未初始化数据段,也被称为"bss - block started by symbol"段.
与数据段相对,不是由程序员进行全局变量 or 静态变量的初始化,而是在程序开始执行时由系统初始化为0. -
Stack
栈区域通常和堆区是相邻的并且是往相对的方向生长,通常当栈指针生长到和堆指针相等代表空闲内存耗完. Stack 是后进先出的数据结构
局部变量存放在Stack,函数调用也依托于Stack(函数的形参就是通过Stack进行传递)
*Heap
堆是动态分配的内存区域, 通常开始bss段结束的位置,然后向上生长. 堆区域是由malloc、reallo和free进行管理的, 也就是说malloc、realloc申请的内存是在堆区域.
示例演示
通过Linux下的size指令来解释说明,代码段、数据段、bss段的构成.
示例一,
#include <stdio.h>
int main(void)
{
return 0;
}
➜ test gcc -o memory-layout memory-layout.c
➜ test size memory-layout
text data bss dec hex filename
1415 544 8 1967 7af memory-layout
数据段大小为: 544
bss段数据大小为: 8
示例二,
#include <stdio.h>
int g_v; /* 未初始化的全局变量存储在 bss*/
int g_l;
int main(void)
{
return 0;
}
➜ test gcc -o memory-layout memory-layout.c
➜ test size memory-layout
text data bss dec hex filename
1415 544 16 1975 7b7 memory-layout
如上所示,在增加未初始化的全局变量后,bss段变大,text、data未有任何变化.
示例三,
#include <stdio.h>
int g_v; /* 未初始化的全局变量存储在 bss*/
int g_l;
int main(void)
{
static int i; /* 未初始化的静态变量 存储在 bss */
static int j; /* 未初始化的静态变量 存储在 bss */
return 0;
}
➜ test gcc -o memory-layout memory-layout.c
➜ test size memory-layout
text data bss dec hex filename
1415 544 24 1983 7bf memory-layout
如上所示,在增加未初始化静态变量的定义后,bss段再一次变大
示例四,
#include <stdio.h>
int g_v; /* 未初始化的全局变量存储在 bss*/
int g_l;
int main(void)
{
static int i = 100; /* 始化的静态变量 存储在 数据段 */
static int j = 100; /* 始化的静态变量 存储在 数据段*/
return 0;
}
➜ test gcc -o memory-layout memory-layout.c
➜ test size memory-layout
text data bss dec hex filename
1415 552 16 1983 7bf memory-layout
如上所示,基于示例三进行静态变量的初始化后,data段变大,而bss段变小.
示例五,
#include <stdio.h>
int g_v = 10; /* 初始化的全局变量存储在 数据段*/
int g_l = 10;
int main(void)
{
static int i = 100; /* Initialized static variable stored in DS*/
static int j = 100;
return 0;
}
➜ test gcc -o memory-layout memory-layout.c
➜ test size memory-layout
text data bss dec hex filename
1415 560 8 1983 7bf memory-layout
如上所示,基于示例四,进行全局变量的初始化后,data段进一步变大,而bss段进一步变小.
示例六,
#include <stdio.h>
int g_v = 10; /* 初始化的全局变量存储在 数据段*/
int g_l = 10;
int main(void)
{
static int i = 100; /* Initialized static variable stored in DS*/
static int j = 100;
if(i == 100)
printf("Hello \r\n");
return 0;
}
➜ test gcc -o memory-layout memory-layout.c
➜ test size memory-layout
text data bss dec hex filename
1526 616 8 2150 866 memory-layout
如上所示,在基于示例五,增加if等指令后,text段变大.
总结
无论是学习C语言还是C++,对于程序内存分布的理解是非常重要的一环节,对于嵌入式开发中一定要理解C程序的内存分布情况.