APUE中的一个典型C内存空间分布
名称 | 内容 |
---|---|
栈 | 局部变量、函数参数、局部常量 |
堆 | 动态内存分配 |
DATA段 | 已初始化全局变量、已初始化全局静态变量、已初始化局部静态变量 |
BSS段 | 未初始化全局变量,未初始化全局静态变量 |
文字常量区 | 字符串常量、全局const常量 |
代码段 | 可执行代码 |
简介
- 栈(stack):存放函数的参数值、返回值、局部变量的值,以及在进行任务切换时存放当前任务的上下文内容。
- 堆(heap):用于动态内存分配,即使用malloc/free系列函数来管理的内存空间。
- DATA段(data segment):包含静态初始化的数据,所以有初值的全局变量和static变量在data区。段的起始位置也是由连接定位文件所确定,段的大小在编译连接时自动分配,其大小与程序使用到的全局变量,常量数量相关。 该段包含了在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)。数据段属于静态内存分配。
- BSS(Block Started by Symbol):通常是指用来存放程序中未初始化的全局变量的一块内存区域,在程序载入时由内核清0。未初始化数据是在程序中声明,但是没有初始化的变量,这些变量在程序运行之前不需要占用存储器的空间。一般是没有初始化的全局变量和没有初始化的静态局部变量。未初始化数据段只有在运行的初始化阶段才会产生,因此它的大小不会影响目标文件的大小。BSS段属于静态内存分配。
- 文字常量区:常量占用内存,只读状态,决不可修改。常量字符串就是放在这里的,程序结束后由系统释放。特殊的常量存储区,属于静态存储区。
- 代码段(code segment/text segment):在AT91库中是表示程序段的大小,它是由编译器在编译连接时自动计算的,当你在链接定位文件中将该符号放置在代码段后,那么该符号表示的值就是代码段大小,编译连接时,该符号所代表的值会自动代入到源程序中。(在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等)。
详解
- 是否占用可执行文件的大小:全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存于.data段中,所以.data和.bss一个重要的区别就是.bss并不占用可执行文件的大小,它只是记载需要多少空间来存储这些未初始化数据,而不分配实际的空间。
- 动/静态分配内存:通过malloc()动态分配的内存,需要程序员手工调用free()释放内存,否则容易导致内存泄露,而静态分配的内存则在进程执行结束后系统释放(Text, Data), 但Stack段中的数据很短暂,函数退出立即被销毁。
- 可执行二进制程序 = 代码段(text) + 数据段(data) + BSS段
- 正在运行的C程序 = 代码段 + 初始化数据段(data) + 未初始化数据段(BSS) + 堆 + 栈
- 数据段(包括3部分)
- 已初始化的读写数据段(.data):已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并且有初值,以供程序运行时读写。在程序中一般为已经初始化的全局变量,已经初始化的静态局部变量(static修饰的已经初始化的变量)。
- 未初始化段(.bss):通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。特点是可读写的,在程序执行之前BSS段会自动清0。
- 只读数据段:通常是指用来存放程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。一般是const修饰的变量以及程序中使用的文字常量一般会存放在只读数据段中。
- 静态存储方式:指在程序编译期间分配固定的存储空间的方式。该存储方式通常是在变量定义时就分定存储单元并一直保持不变, 直至整个程序结束。全局变量,静态变量等就属于此类存储方式。
- **静态存储区:数据段和代码段。**一定会存在的而且会永恒存在、不会消失,这样的数据包括常量、常变量(const 变量)、静态变量、全局变量等。静态 、常量、全局变量就是存放在静态存储区,他们在程序编译完成后就已经分配好了,生命周期持续至程序结束。
- 动态存储方式:指在程序运行期间根据需要进行动态的分配存储空间的方式。动态存储变量是在程序执行过程中,使用它时才分配存储单元, 使用完毕立即释放。 典型的例子是函数的形式参数,在函数定义时并不给形参分配存储单元,只是在函数被调用时,才予以分配,调用函数完毕立即释放。如果一个函数被多次调用,则反复地分配、释放形参变量的存储单元。
- **动态存储区:栈和堆。**栈:会存放函数的返回地址、参数和局部变量。堆:我们通过 new 算符和 malloc 函数分配得到的空间。
实例
代码
// 运行环境为 vs2019
#include "stdio.h"
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
const int g_A = 10; // 代码段,const 常量
int g_B = 20; // 数据段,已初始化,全局变量
int g_C; // BSS段,未初始化,全局变量
int g_F = 0; // BSS段,初始化为0,全局变量
static int g_D = 30; // 数据段,已初始化,静态全局变量
static int g_E; // BSS段,未初始化,静态全局变量
char* g_p; // BSS段,未初始化,全局指针变量,默认值为0
void main()
{
const char* local_cp = "1234"; // p3在栈上,123456在代码段
const int local_F = 10; // 栈,局部 const 常量
int local_A; // 栈,未初始化,局部变量
int local_B = 30; // 栈,已初始化,局部变量
static int local_C = 30; // 数据段,已初始化,静态局部变量
static int local_D = 0; // BSS段,已初始化为0,静态局部变量
static int local_E; // BSS段,未初始化,静态局部变量
g_p = (char*)malloc(10*sizeof(char)); //堆,分配得来得10字节的区域在堆区
if (g_p == 0)
return;
//1234{post.content}放在常量区,编译器可能会将它与p3所指向 的"123456"优化成一块
strcpy_s(g_p, 5, local_cp);
printf("\n");
printf("------------------------ 高地址 ----------------------------\n");
printf("\n");
printf("===================== 栈( 向下增长 ) =======================\n");
printf("栈, 局部cost指针常量, &local_cp,addr: 0x%p\n", &local_cp);
printf("栈, 局部cost常量, local_F, addr: 0x%p\n", &local_F);
printf("栈, 局部变量, 未初始化, local_A, addr: 0x%p\n", &local_A);
printf("栈, 局部变量, 已初始化, local_B, addr: 0x%p\n", &local_B);
printf("\n");
printf("堆, malloc分配内存, g_p, addr: 0x%p\n", g_p);
printf("===================== 堆( 向上增长 ) =======================\n");
printf("\n");
printf("BSS段, 静态局部变量, 未初始化, local_E, addr: 0x%p\n", &local_E);
printf("BSS段, 静态局部变量, 初始化为0, local_D, addr: 0x%p\n", &local_D);
printf("BSS段, 静态全局变量, 未初始化, g_E, addr: 0x%p\n", &g_E);
printf("BSS段, 全局指针变量, 未始化 &g_p, addr: 0x%p\n", &g_p);
printf("BSS段, 全局变量, 初始化为0 g_F, addr: 0x%p\n", &g_F);
printf("BSS段, 全局变量, 未初始化 g_C, addr: 0x%p\n", &g_C);
printf("========================== BSS段 ===========================\n");
printf("\n");
printf("数据段,静态局部变量, 已初始化, local_C, addr: 0x%p\n", &local_C);
printf("数据段,静态全局变量, 已初始化, g_D, addr: 0x%p\n", &g_D);
printf("数据段,全局变量, 已初始化 g_B, addr: 0x%p\n", &g_B);
printf("========================= DATA段 ===========================\n");
printf("\n");
printf("代码段, 只读常量, local_cp, addr: 0x%p\n", local_cp);
printf("代码段,全局初始化变量, 只读const, g_A, addr: 0x%p\n", &g_A);
printf("========================= 代码段 ===========================\n");
printf("\n");
printf("------------------------- 低地址 ---------------------------\n");
printf("\n");
return;
}
运行结果
参考
https://blog.youkuaiyun.com/chen1083376511/article/details/54930191
https://www.cnblogs.com/bigbigtree/archive/2012/11/23/2784137.html
t/chen1083376511/article/details/54930191
https://www.cnblogs.com/bigbigtree/archive/2012/11/23/2784137.html
May 25, 2020 PM 16:54 @DaYang