内存区划分

在这里插入图片描述

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

站在汇编语言的角度,一个程序分为:
数据段 – 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.youkuaiyun.com/love_gaohz/article/details/41310597

<think>好的,用户想了解内存划分的原理及实现方法,特别是在计算机体系结构中的相关内容。首先,我需要回忆内存管理的基本概念,然后结合提供的引用资料来组织答案。 内存划分主要涉及物理内存和虚拟内存的管理。物理内存划分包括固定分区和动态分区,这在早期的操作系统中常见。固定分区是将内存划分为固定大小的区域,每个进程分配到合适的区域,但可能造成内部碎片。动态分区则根据进程需求动态分配,减少碎片但需要处理外部碎片的问题,比如引用中的MMIO技术,可能和内存映射有关,但需要确认是否相关。 虚拟内存方面,分页机制是关键,如x86_64处理器使用48位虚拟地址,分成页目录索引和页表索引,剩下的位作为页内偏移。引用4提到虚拟地址的布局,这可能涉及分页机制的具体实现。分页通过页表将虚拟地址转换为物理地址,支持更大的地址空间和内存保护。 此外,内存映射I/O(MMIO)在引用3中被提及,设备寄存器被映射到内存地址,这样访问特定内存地址就能操作设备IO。这可能属于内存划分中的一部分,用于外设与内存的统一编址。 内存保护机制如基址-界限寄存器,确保进程不能访问其他区域,这在现代CPU中常见。引用1提到的纹理内存属于GPU的优化,可能和缓存机制有关,但用户的问题更偏向通用计算机架构,这部分可能作为扩展提及。 需要将上述内容结构化,先讲物理内存划分,再虚拟内存,然后是MMIO和内存保护,最后实现方法如分页、分段、内存分配算法等。同时要结合提供的引用资料,特别是引用3和4,确保引用正确。 可能生成的问题需要覆盖内存划分类型、虚拟内存分页、MMIO、内存保护等,确保用户能进一步探索相关主题。需要检查引用是否准确对应到相关内容,比如引用3对应MMIO,引用4对应虚拟地址布局。</think>### 内存划分原理及实现方法 #### 一、内存划分的基本原理 内存划分是计算机体系结构中管理物理和虚拟内存的核心机制,主要目标包括资源分配优化、进程隔离和硬件抽象。其核心原理可分为以下两类: 1. **物理内存划分** - **固定分区**:早期操作系统将物理内存划分为固定大小的区域,每个进程分配至合适的分区[^1]。例如,1MB内存划分为4个256KB分区。 - **动态分区**:根据进程需求动态分配连续内存块,需处理外部碎片(如通过紧凑技术合并空闲区域)。 2. **虚拟内存划分** - **分页机制**:将虚拟地址空间和物理内存划分为固定大小的页(如4KB),通过页表实现映射。例如,x86_64架构使用48位虚拟地址划分,其中高16位未使用,中间部分为页目录和页表索引,低12位为页内偏移[^4]。 - **分段机制**:按逻辑单元(代码段、数据段)划分内存,提供更细粒度的保护。 #### 二、关键实现技术 1. **地址转换与页表** - 虚拟地址通过多级页表转换为物理地址,例如x86_64使用四级页表(PML4、PDPT、PD、PT)。 - 示例:虚拟地址`0xFFFF8000 00000000`可能映射到物理地址`0x200000`。 2. **内存映射I/O(MMIO)** - 外设寄存器通过内存地址映射实现访问。例如ARM架构中,设备IO地址`0x02020000`可直接通过指针操作[^3]。 ```c int *four_byte_io = (int *)0x02020001; // 内存映射IO示例 *four_byte_io = 123456; // 写入设备寄存器 ``` 3. **内存保护机制** - 基址-界限寄存器:限制进程访问范围。 - 页表权限位:标记页的读写执行权限。 #### 三、优化策略 1. **缓存机制** 如纹理内存通过空间局部性优化访问效率[^1]。 2. **内存分配算法** - 首次适应(First Fit) - 伙伴系统(Buddy System) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值