4G虚拟地址空间布局

本文详细解析了4G虚拟地址空间布局,包括1G内核空间和3G用户空间的划分,阐述了不可访问区域、代码段、数据段、BSS段、堆、栈、命令行参数和环境变量等概念,以及内核空间的DMA、NORMAL和HIGHMEM区域的作用。

4G虚拟地址空间布局

 

 

4G的虚拟内存空间:

其中1G是属于内核空间,另外的3G属于用户空间

所有的进程都拥有属于自己的用户空间,但却共享一个内核空间

 

现在我们从上向下开始分析

首先是用户空间:

①:128M大小的不可访问区域(保留区)

我们通常将申请的临时指针变量初始化时置为NULL,可以防止后续无意使用这个指针出错,因为NULL == 0x0,将其指针指向0x0这个地址时,因为0x0这个地址属于保留区,没有访问权限的。

②:.text代码段

这个区域存储的是代码中的指令。

指令:一份代码是由数据和指令构成的,除数据外剩下的都叫做指令,另外,局部变量也属于指令,但是局部变量存储在栈上,代码运行时才在栈中预留好的区域中开辟。

 

③:.data数据段

这个区域存储的是代码中的各种数据,包括全局变量,静态局部变量,但两者必须为已初始化且初始化不为零的数据

 

④:.bss段

这个区域存储也是代码中的各种数据,不过存储的是未初始化或者是初始化了但是为零的数据。

这个段其实在可执行文件中不占空间,(.bss段)在段表中保存着,因为它记录的都是一些未初始化的值要不就是初始化了但是为零的值,我们可以只记录符号和符号所要占用的大小,在程序运行时,才进行开辟并将其空间全部清零。可以用readelf -S或者objdump -h 查看

 

⑤:堆

当我们需要申请一块连续且指定大小的内存块的动态内存时,需要在堆中申请。需要手动申请,手动释放。不释放会造成内存泄漏。

 

⑥:栈

所有局部变量存储在这里,且函数的运行也需要栈的开辟,不过空间释放由系统完成。

 

⑦:命令行参数

int main()

{

//这是我们平常写的main函数

}

其实它长这样

int main(int argc, char *argv[],char *envp[])

{

//这是真实的main函数

}

 

前两个参数大家都很熟悉,argc是命令行参数的个数,不指定时默认为1,是当前文件名,char *argv[] 也可以写成char **argv,其中argv[0]默认保存的就是argc == 1时的程序名。如果在执行程序时后面跟随指令,则argc的值和argv[]中的元素就会发生变化。

然而这第三个参数是什么意思呢?在我们调用一些系统库函数的时候,我们需要使用预处理指令#include。但是我们系统怎么知道去哪个路径寻找这些头文件的函数定义呢?就是通过char *envp[](环境变量)来实现的。

 

话说回来,命令行参数就是我们的argv了。里面存放着我们的程序名,以及参数(如果你给了的话)。

⑧:环境变量

就是在第⑦条中介绍的,main函数的第三个参数。

 

 

 

我们再来看一下内核空间:

①:内存直接访问(ZONE_DMA(大约16MB)

全名ZONE_DirectMemoryAccess(直接内存访问),可以加快磁盘和内存之间数据的交换,不需要经过CPU的寄存器,这时CPU可以去干别的事,大大增加了效率。

 

②:ZONE_NORMAL (大约892MB)

内核中最重要最常用的部分。用于直接映射。PCB就在这里。

③:ZONE_HIGHMEM (128MB)

所谓的高端内存,用于在内核中映射高于1G的物理内存时使用。64位系统则没有该段(根本不需要,因为64位操作系统给内核空间分配的内存达到512G)。

<think>我们正在讨论的是每个进程都有4G虚拟空间的相关知识。根据引用[1]和引用[2],我们可以总结如下: 1. 在32位操作系统中,每个进程都拥有4GB的虚拟地址空间。这4GB空间被划分为用户空间(0~3GB)和内核空间(3GB~4GB)。注意,这里的4GB是指寻址能力,即进程可以使用从0到0xFFFFFFFF的地址,但并不意味着实际拥有4GB物理内存。 2. 每个进程的用户空间是独立的,即不同进程的相同虚拟地址会被映射到不同的物理地址。而内核空间在所有进程中是共享的,即所有进程的3GB~4GB虚拟地址映射到相同的物理内存区域(内核代码和数据)。 3. 虚拟地址通过页表映射到物理地址。每个进程都有自己的页表,用于映射其用户空间;而内核空间的映射在进程间是相同的,通常在内核初始化时建立,并在进程创建时被共享。 4. 进程实际使用的内存远小于4GB,因为虚拟地址空间中的大部分区域并未映射到物理内存。进程通过内存区域(VMA)来管理已使用的虚拟地址范围。 5. 当进程通过malloc等函数申请内存时,实际上是在用户空间的堆区分配虚拟地址,并可能通过缺页中断分配物理页面。 6. 在创建子进程(fork)时,子进程会复制父进程的虚拟地址空间(写时复制机制),因此子进程拥有与父进程相同的4GB虚拟地址布局,但实际物理页面只有在写入时才会单独分配。 下面,我们将详细展开这些知识点。 </think> ### 每个进程拥有4GB虚拟地址空间的原理详解 #### 一、核心概念:虚拟地址空间 1. **基本定义** - 32位系统中,每个进程拥有**独立的4GB虚拟地址空间**($2^{32} = 4,294,967,296$字节) - 这是**寻址能力**而非实际物理内存占用[^1] - 物理内存通过页表动态映射到虚拟地址 2. **空间划分原理** ```mermaid graph LR A[4GB虚拟空间] --> B[用户空间 0-3GB] A --> C[内核空间 3GB-4GB] B --> D[代码段] B --> E[数据段] B --> F[堆区] B --> G[栈区] C --> H[内核代码] C --> I[设备映射] C --> J[物理内存映射] ``` #### 二、关键技术实现机制 1. **页表映射原理** - 进程通过**页表**将虚拟地址转换为物理地址 $$ \text{虚拟地址} \xrightarrow{\text{页表查询}} \text{物理地址} $$ - 页表由操作系统维护,进程切换时更新CR3寄存器 2. **写时复制(Copy-on-Write)** - fork()创建子进程时: - 父子进程**共享**相同的物理页 - 当任一进程尝试写入时,触发缺页中断 - 内核分配新物理页并复制数据[^2] ```c // 伪代码:写时复制处理 if (page_write_attempt && page_is_shared) { allocate_new_page(); copy_page_content(); update_page_table(); } ``` 3. **内存区域管理(VMA)** - 内核通过**vm_area_struct**结构记录进程内存使用: ```c struct vm_area_struct { unsigned long vm_start; // 起始地址 unsigned long vm_end; // 结束地址 struct file *vm_file; // 映射文件 pgprot_t vm_page_prot; // 访问权限 }; ``` - 实际内存占用由VMA链表管理,远小于4GB[^1] #### 三、用户空间与内核空间交互 1. **内核空间特性** - 所有进程共享**相同的1GB内核空间**(3GB-4GB) - 包含: - 直接映射区:896MB物理内存的1:1映射 - 动态映射区:128MB用于映射高位内存[^1] - 用户进程通过**系统调用**进入内核空间 2. **地址隔离机制** | 访问方向 | 权限控制 | 硬件支持 | |----------------|----------------------------|-------------| | 用户→内核 | 禁止直接访问(触发异常) | 特权级保护 | | 内核→用户 | 需用copy_from_user() | SMAP/SMEP | #### 四、实际内存使用分析 1. **典型进程内存布局** ``` 0x08048000-0x0804c000 代码段 (16KB) 0x0804c000-0x0804d000 数据段 (4KB) 0x09e00000-0x0a000000 堆区 (2MB) 0xbfd00000-0xbffff000 栈区 (2MB) ...(其余99.9%地址空间未映射)... 0xc0000000-0xffffffff 内核空间 ``` 2. **资源消耗对比** | 资源类型 | 虚拟空间占用 | 实际物理内存占用 | |----------------|-------------|-----------------| | 进程控制块 | 4GB概念空间 | 约1KB | | 页表 | 4GB概念空间 | 4-8MB | | 堆分配1MB | 1MB地址范围 | 1MB物理页 | #### 五、设计优势与挑战 1. **核心优势** - **进程隔离**:一个进程崩溃不影响其他进程 - **内存超额分配**:总和>4GB的虚拟内存可映射到有限物理内存 - **简化编程**:连续虚拟地址隐藏物理碎片 2. **性能优化技术** - **大页(Hugepage)**:减少TLB缺失率 ```bash # 配置2MB大页 echo 1024 > /proc/sys/vm/nr_hugepages ``` - **地址空间随机化(ASLR)**:增强安全性 ```bash # 查看ASLR状态 cat /proc/sys/kernel/randomize_va_space ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值