欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

内存区划分

程序员文章站 2022-06-03 13:24:47
...

内存区划分

一.内存分配(汇编语言/高级语言)

站在汇编语言的角度,一个程序分为:
数据段 – DS
堆栈段 – SS
代码段 – CS
扩展段 – ES
站在高级语言的角度,根据APUE,一个程序分为如下段:
text
data (initialized)
bss
stack
heap

1.一般情况下,一个可执行二进制程序(更确切的说,在Linux操作系统下为一个进程单元,在UC/OSII中被称为任务)在存储(没有调入到内存运行)时拥有3个部分,分别是代码段(text)、数据段(data)和BSS段。这3个部分一起组成了该可执行程序的文件。
★★可执行二进制程序 = 代码段(text)+数据段(data)+BSS段★★
2.而当程序被加载到内存单元时,则需要另外两个域:堆域和栈域。图1-1所示为可执行代码存储态和运行态的结构对照图。一个正在运行的C程序占用的内存区域分为代码段、初始化数据段、未初始化数据段(BSS)、堆、栈5个部分。
★★正在运行的C程序 = 代码段+初始化数据段(data)+未初始化数据段(BSS)+堆+栈★★
3.在将应用程序加载到内存空间执行时,操作系统负责代码段、数据段和BSS段的加载,并将在内存中为这些段分配空间。栈亦由操作系统分配和管理,而不需要程序员显示地管理;堆段由程序员自己管理,即显示地申请和释放空间。
4.动态分配与静态分配,二者最大的区别在于:1. 直到Run-Time的时候,执行动态分配,而在compile-time的时候,就已经决定好了分配多少Text+Data+BSS+Stack。2.通过malloc()动态分配的内存,需要程序员手工调用free()释放内存,否则容易导致内存泄露,而静态分配的内存则在进程执行结束后系统释放(Text, Data), 但Stack段中的数据很短暂,函数退出立即被销毁。
内存区划分
图1-1(从可执行文件a.out的角度来讲,如果一个数据未被初始化那就不需要为其分配空间,所以.data和.bss一个重要的区别就是.bss并不占用可执行文件的大小,它只是记载需要多少空间来存储这些未初始化数据,而不分配实际的空间)

二.划分

1.代码段 --text(code segment/text segment)

text段在内存中被映射为只读,但.data和.bss是可写的。
text段是程序代码段,在AT91库中是表示程序段的大小,它是由编译器在编译连接时自动计算的,当你在链接定位文件中将该符号放置在代码段后,那么该符号表示的值就是代码段大小,编译连接时,该符号所代表的值会自动代入到源程序中。

2.数据段 – data

data包含静态初始化的数据,所以有初值的全局变量和static变量在data区。段的起始位置也是由连接定位文件所确定,大小在编译连接时自动分配,它和你的程序大小没有关系,但和程序使用到的全局变量,常量数量相关。数据段属于静态内存分配。

3.bss段–bss

bss是英文Block Started by Symbol的简称,通常是指用来存放程序中未初始化的全局变量的一块内存区域,在程序载入时由内核清0。BSS段属于静态内存分配。它的初始值也是由用户自己定义的连接定位文件所确定,用户应该将它定义在可读写的RAM区内,源程序中使用malloc分配的内存就是这一块,它不是根据data大小确定,主要由程序中同时分配内存最大值所确定,不过如果超出了范围,也就是分配失败,可以等空间释放之后再分配。BSS段属于静态内存分配。

4.stack:

栈(stack)保存函数的局部变量(但不包括static声明的变量, static 意味着 在数据段中 存放变量),参数以及返回值。是一种“后进先出”(Last In First Out,LIFO)的数据结构,这意味着最后放到栈上的数据,将会是第一个从栈上移走的数据。对于哪些暂时存贮的信息,和不需要长时间保存的信息来说,LIFO这种数据结构非常理想。在调用函数或过程后,系统通常会清除栈上保存的局部变量、函数调用信息及其它的信息。栈另外一个重要的特征是,它的地址空间“向下减少”,即当栈上保存的数据越多,栈的地址就越低。栈(stack)的顶部在可读写的RAM区的最后。

5.heap:

堆(heap)保存函数内部动态分配内存,是另外一种用来保存程序信息的数据结构,更准确的说是保存程序的动态变量。堆是“先进先出”(First In first Out,FIFO)数据结构。它只允许在堆的一端插入数据,在另一端移走数据。堆的地址空间“向上增加”,即当堆上保存的数据越多,堆的地址就越高。
内存区划分

下图是APUE中的一个典型C内存空间分布图:
内存区划分
所以可以知道传入的参数,局部变量,都是在栈顶分布,随着子函数的增多而向下增长.
函数的调用地址(函数运行代码),全局变量,静态变量都是在分配内存的低部存在,而malloc分配的堆则存在于这些内存之上,并向上生长.

三.instance analysis

#include <stdio.h>


const int g_A = 10; //代码段
int g_B = 20; //数据段
static int g_C = 30; //数据段
static int g_D; //BSS段
int g_E; //BSS段
char *p1; //BSS段


int main( )
{
    int local_A; //栈
    int local_B; //栈
    static int local_C = 0; //数据段
    static int local_D; //数据段
    char *p3 = "123456"; //123456在代码段,p3在栈上
    p1 = (char *)malloc( 10 ); //堆,分配得来得10字节的区域在堆区
    strcpy( p1, "123456" ); //123456{post.content}放在常量区,编译器可能会将它与p3所指向 的"123456"优化成一块
    printf("hight address\n");
    printf("-------------栈--------------\n");
    printf( "栈, 局部变量, local_A, addr:0x%08x\n", &local_A );
    printf( "栈, 局部变量,(后进栈地址相对local_A低) local_B, addr:0x%08x\n", &local_B );
    printf("-------------堆--------------\n");
    printf( "堆, malloc分配内存, p1, addr:0x%08x\n", p1 );
    printf("------------BSS段------------\n");
    printf( "BSS段, 全局变量, 未初始化 g_E, addr:0x%08x\n", &g_E, g_E );
    printf( "BSS段, 静态全局变量, 未初始化, g_D, addr:0x%08x\n", &g_D );
    printf( "BSS段, 静态局部变量, 初始化, local_C, addr:0x%08x\n", &local_C);
    printf( "BSS段, 静态局部变量, 未初始化, local_D, addr:0x%08x\n", &local_D);
    printf("-----------数据段------------\n");
    printf( "数据段,全局变量, 初始化 g_B, addr:0x%08x\n", &g_B);
    printf( "数据段,静态全局变量, 初始化, g_C, addr:0x%08x\n", &g_C);
    printf("-----------代码段------------\n");
    printf( "代码段,全局初始化变量, 只读const, g_A, addr:0x%08x\n\n", &g_A);
    printf("low address\n");

    return 0;
}

内存区划分
本文参考:https://blog.csdn.net/love_gaohz/article/details/41310597

相关标签: 内存分析