堆内存相关
定义和特点
- 堆内存是程序运行时动态分配的内存区域,由开发者手动申请和释放(如
C中的malloc/free、C++的new/delete) - 具有以下特点
- 生命周期长:内存存活周期由开发者控制,不随函数调用结束而释放
- 空间大且灵活:理论上可分配至系统可用内存上限,适合存储大型对象或动态数据结构(如链表、树)
- 分配速度慢:需通过内存管理器查找可用空间,可能触发内存整理或系统调用
- 管理复杂度高:易引发内存泄漏、碎片化、越界访问等问题
堆内存的分配原理
- 概述
- 堆内存分配依赖于操作系统的内存管理器,其核心流程为:
- 请求内存:程序通过
malloc/new申请指定大小的内存块 - 查找空闲块:内存管理器遍历空闲链表,寻找满足需求的连续空间(常用算法:首次适应、最佳适应)
- 分配与标记:若找到合适块,分割并标记为已使用;若不足则触发扩容(如通过
brk或mmap系统调用) - 释放与合并:调用
free/delete后,内存块被标记为空闲,并尝试合并相邻空闲块以减少碎片
Windows内存管理器
概念
Windows内存管理器是操作系统内核的核心组件(内核模式内存管理器),负责管理物理内存、虚拟内存以及内存映射文件等资源
Windows内存管理器具体分配内存的过程
- 虚拟地址申请
- 进程通过
API(如VirtualAlloc)申请虚拟地址空间,系统根据请求大小保留或提交内存 - 内存分配粒度通常为
64KB(区域粒度)和4KB(页面粒度)
- 进程通过
- 物理内存映射
- 页目录与页表
虚拟地址通过CPU的CR3寄存器找到页目录表(Page Directory),再通过页表(Page Table)逐级转换为物理地址
例如,虚拟地址0x12345678的高10位定位页目录项,中间10位定位页表项,低12位为页内偏移 - 页面状态管理
页面可能处于空闲、保留、提交或共享状态
系统通过工作集(Working Set)跟踪活跃页面
- 页目录与页表
- 内存池优化
- 系统缓存:缓存频繁访问的文件数据,减少磁盘
I/O - 非分页池与分页池:内核组件使用非分页池(不可交换到页文件),驱动程序和用户程序使用分页池(可交换)
- 系统缓存:缓存频繁访问的文件数据,减少磁盘
Windows内存管理器内存回收机制
- 内存回收通过动态调整和置换策略实现资源高效利用:
- 页面置换算法:
LRU(最近最少使用):优先淘汰长时间未访问的页面- 工作集修剪:当物理内存不足时,系统将非活跃页面移至页文件,释放物理内存
- 内存压缩技术:
Windows 10后引入内存压缩(压缩不活跃页面),减少对页文件的依赖,提升响应速度
- 显式释放与合并:
- 进程调用
VirtualFree释放虚拟地址空间,系统标记页面为可回收 - 堆管理器(如
HeapFree)合并相邻空闲块,减少外部碎片
- 进程调用
- 异常处理与保护:
- 访问非法地址或已释放内存时,触发
STATUS_ACCESS_VIOLATION异常,终止进程防止系统崩溃
- 访问非法地址或已释放内存时,触发
物理内存
- 物理内存通过分页机制划分为固定大小的块(通常
4KB),页文件(如pagefile.sys)作为物理内存的扩展,用于存储不活跃的页面
物理内存的分页机制
分页机制的核心概念
- 分页机制是操作系统管理物理内存的核心技术,通过将物理内存划分为固定大小的块(页框,
Page Frame),并将进程的虚拟地址空间划分为相同大小的页(Page),实现虚拟内存与物理内存的动态映射 - 固定页大小:通常为
4KB(如Windows系统),也有大页(如8KB或4MB)用于特殊场景 - 离散分配:进程的页可以分散存储在物理内存的不同页框中,无需连续空间,解决了外部碎片问题
- 虚拟地址映射:通过页表(
Page Table)实现逻辑地址到物理地址的转换,每个进程拥有独立的页表
分页机制的关键结构
- 页表与页目录表:
- 页表:存储虚拟页号到物理页框号的映射关系,每个页表项(
PTE)占4字节(32位系统),包含物理页框号及权限标志(如读/写/执行) - 页目录表:在二级分页机制中,页目录表存储页表的物理地址,通过虚拟地址的高
10位索引
CR3寄存器:存储当前进程页目录表的物理地址,是地址转换的起点
- 页表:存储虚拟页号到物理页框号的映射关系,每个页表项(
- 多级页表
- 当物理内存超过
4GB时,采用多级页表(如2-9-9-12分页机制),扩展页表项为64位以支持更大物理地址空间 - 例如,
Windows系统的10-10-12分页机制支持4GB物理内存,而PAE(物理地址扩展)模式通过三级页表支持更大内存
- 当物理内存超过
地址转换流程
- 虚拟地址到物理地址的转换通过硬件(
MMU)完成,步骤如下:- 拆分虚拟地址:例如
32位地址拆分为高10位(页目录索引)、中间10位(页表索引)、低12位(页内偏移) - 查页目录表:通过
CR3寄存器找到页目录表基址,用高10位索引获取页表物理地址 - 查页表:用中间
10位索引页表,获取物理页框号 - 拼接物理地址:物理页框号左移
12位(4KB对齐)后加上页内偏移,得到最终物理地址
- 拆分虚拟地址:例如
- 示例:
- 虚拟地址
0x1D16H(二进制0001 1101 0001 0110)在4KB分页下,页号为1,页内偏移为0xD16,若页表项指向物理页框3,则物理地址为0x3D16H
- 虚拟地址
物理内存相关总结(记忆)
- 物理内存是通过分页机制被划分为许多固定大小的块(页框或者物理页,
Page Frame) - 每个页框都有唯一的编号,用来标识它在物理内存中的位置
- 而这些页框的编号和权限信息,又会被页表保存
- 在多级分页机制中,一级页表(或者叫页目录表)保存了二级页表的物理地址,而二级页表则保存了多个虚拟页到物理页(也就是页框)的映射关系,
- 在
32位系统里面,CPU的CR3寄存器保存了页目录表的物理地址,而虚拟地址的高10位是页目标表的索引,中间10位则是页表的索引,低12位则是页内的偏移 - 虚拟地址和物理地址就是这样映射的
虚拟内存
- 通过分页技术(
Page File)将物理内存与硬盘空间结合,为每个进程提供独立的4GB虚拟地址空间(32位系统) - 虚拟内存分为三个主要区域:
- 用户模式分区(
0x00000000-0x7FFFFFFF):进程独享,存储代码、堆、栈等数据 - 内核模式分区(
0x80000000-0xFFFFFFFF):共享系统内核、驱动程序和内存池 NULL指针保护区(0x00000000-0x0000FFFF):防止非法访问空指针
- 用户模式分区(
虚拟内存的分页技术
分页机制的核心概念
- 分页技术是虚拟内存的核心实现机制,通过将虚拟内存与物理内存划分为固定大小的页(如
4KB),并建立页表实现地址映射,其核心逻辑如下:
分页机制的基本结构
- 页与页框
- 虚拟内存空间被划分为虚拟页(
Page),物理内存划分为页框(Frame),两者大小相同(如4KB)
- 虚拟内存空间被划分为虚拟页(
- 页表
- 每个进程拥有独立的页表,页表项(
PTE)保存虚拟页到物理页框的映射关系及权限标志(存在位、读写位等)
- 每个进程拥有独立的页表,页表项(
- 多级页表
32位系统采用二级页表(页目录表+页表),64位系统使用四级页表(PGD→PUD→PMD→PTE),通过分级减少页表内存占用
分页技术的关键特性
- 按需加载:
- 虚拟页仅在需要时加载到物理内存,未使用的页保留在硬盘(
Page File)中,减少物理内存占用
- 虚拟页仅在需要时加载到物理内存,未使用的页保留在硬盘(
- 内存保护:
- 通过页表项的权限位(如用户/内核模式、读写限制)隔离进程内存空间,防止非法访问
- 缺页中断(
Page Fault):- 当访问的虚拟页未在物理内存中时,触发缺页中断,操作系统从硬盘加载该页到内存并更新页表
硬件支持
MMU(内存管理单元):- 负责虚拟地址到物理地址的转换,通过页表和
TLB(快表)加速映射
- 负责虚拟地址到物理地址的转换,通过页表和
CR3寄存器:- 存储当前进程页目录表的物理地址,是地址转换的起点
分页技术如何结合硬盘空间提供4GB独立地址空间
- 在
32位系统中,虚拟地址空间为4GB,但物理内存通常远小于此。分页技术通过以下方式实现扩展: - 页表映射与硬盘交换
- 虚拟地址划分:
32位虚拟地址分为三部分:
高10位:索引页目录表(一级页表),定位二级页表的物理基址
中间10位:索引二级页表,获取物理页框号
低12位:页内偏移量(4KB对齐) - 硬盘空间作用
当物理内存不足时,操作系统将不活跃的页换出到硬盘的Page File中,腾出空间加载新页
若进程访问的页在硬盘中,触发缺页中断,由操作系统将页从硬盘加载到物理内存,并更新页表项的存在位
- 虚拟地址划分:
- 进程地址空间的独立性
- 独立页表:每个进程拥有独立的页目录表和页表,通过
CR3寄存器切换页目录基址,确保进程间内存隔离 - 虚拟地址到物理地址的动态映射:
进程的4GB虚拟地址空间通过页表映射到物理内存或硬盘中的Page File,实际物理内存分配是动态且离散的 - 例如,进程
A的虚拟地址0x1000可能映射到物理页框0x2000,而进程B的同一虚拟地址0x1000可能映射到物理页框0x5000或硬盘中的某个位置
- 独立页表:每个进程拥有独立的页目录表和页表,通过
- 性能优化与局限性
TLB加速:高频访问的页表项缓存在TLB中,减少查多级页表的开销- 硬盘延迟问题:频繁换页会导致性能下降(尤其是使用
HDD时),SSD可缓解此问题 - 内存压缩技术:部分系统(如
macOS)压缩内存数据,减少换页需求
页表项
- 页表项(
PTE)不仅包含物理页框编号和权限,还包括以下关键标志位- 存在位(
Present, P):标记该页是否已加载到物理内存(若为0,访问会触发缺页中断) - 读写权限(
R/W):控制页面是否可写(1=可读写,0=只读/执行) - 用户/内核权限(
U/S):标记页面是否允许用户态程序访问(1=允许,0=仅内核态访问) - 访问位(
Accessed, A):记录该页是否被CPU访问过(用于页面置换算法) - 脏位(
Dirty, D):标记页内容是否被修改(若为1,换出时需写回磁盘) - 全局位(
Global, G):标记是否为全局页(TLB缓存中不失效,常用于内核页) - 高速缓存控制位(
PWT/PCD):控制页面的缓存策略(如直写/回写、是否禁用缓存)
- 存在位(
虚拟地址到物理地址的映射机制
VirtualAlloc等函数通过以下步骤建立映射:- 分配虚拟地址范围(不立即分配物理内存)
- 按需填充页目录表和页表项(物理页框可能在首次访问时分配)
- 通过缺页中断触发物理页框的实际分配或从磁盘加载
虚拟内存相关总结(记忆)
- 首先,虚拟内存是通过页表映射和硬盘交换的技术为进程提供了逻辑上的
4GB地址空间 - 然后,这个虚拟地址空间也会被划分为固定大小的页(也叫虚拟页),具体大小与物理内存的页框一致
- 进程启动时,操作系统仅为进程分配虚拟地址空间,但不会立即分配全部物理内存
- 当进程首次访问位于某个虚拟页的虚拟地址时,通过每个进程自己的页表,发现其对应的页表项可能处于未分配或未加载状态,就会触发缺页中断
- 如果是虚拟页未分配物理页框,需从磁盘(如
Page File或文件)加载数据到内存,并更新页表项 - 如果虚拟页已分配物理页框,但尚未加载到内存(如共享库已被其他进程加载)。此时仅需将已存在的物理页框与虚拟页关联
内存保护机制
- 通过权限控制(如可读、可写、可执行)和地址空间隔离,防止进程间内存冲突
疑问与理解
-
关于页目录表和页表的理解
CPU的CR3寄存器保存了进程的页目录表的物理地址- 而在进程的页目录表里面,可能保存了二级页目录表的物理基址(假如存在二级页目录表)
- 而二级页目录表里面保存了很多页表项
- 页表项的内容有物理页框编号,页框的相关权限
-
操作系统为每一个进程维护了一个页表目录吗?
- 操作系统为每个进程维护独立的页目录表,目的是实现进程间内存隔离和按需动态映射:
- 进程切换与
CR3寄存器:CPU通过CR3寄存器存储当前进程的页目录表物理地址
当进程切换时,操作系统更新CR3寄存器,指向新进程的页目录表,从而实现不同进程的地址空间隔离 - 页目录表的独立性:每个进程的页目录表仅包含其实际使用的虚拟地址区域的映射关系,未使用的二级页表可能不存在,按需分配
- 内核空间的共享性:虽然用户空间的页目录表独立,但内核空间的页表项(如操作系统内核代码和数据)可能被所有进程共享,通过全局页表(
Global Page Table)实现
-
物理内存不足时的换页机制
- 当物理内存不足且访问的页未加载(存在位
P=0)时,触发缺页中断 - 作系统根据页面置换算法(如
LRU、时钟算法)选择不活跃的页,将其内容写入Page File(若脏位D=1) - 将所需页从
Page File加载到物理内存,更新页表项的存在位和物理页框号
- 当物理内存不足且访问的页未加载(存在位
-
物理内存会被划分为固定大小的块(页框,
Page Frame),并且进程的虚拟地址空间也会被划分为相同大小的页(Page),具体是怎么实现虚拟内存与物理内存的动态映射?- 物理内存被划分为页框(如
4KB大小),每个页框有唯一的物理地址 - 进程的虚拟地址空间被划分为虚拟页,大小与页框相同(如
4KB) - 页表(
Page Table)记录虚拟页到物理页框的映射关系,每个进程拥有独立的页表
页目录表(一级页表):存储二级页表的物理基地址和权限标志
二级页表:存储虚拟页到物理页框的映射项(PTE),每个PTE包含物理页框号、存在位(Present)、读写权限(R/W)等标志 - 若
PTE的存在位为0,表示该页未加载到物理内存,会触发缺页中断 - 如果是虚拟页未分配物理页框,需从磁盘(如
Page File或文件)加载数据到内存,并更新页表项 - 如果虚拟页已分配物理页框,但尚未加载到内存(如共享库已被其他进程加载)。此时仅需将已存在的物理页框与虚拟页关联
- 总结的话,就是:
- 进程启动时,操作系统仅为进程分配虚拟地址空间,但不会立即分配全部物理内存
当进程首次访问位于某个虚拟页的虚拟地址时,其对应的页表项可能处于未分配或未加载状态,此时会触发缺页中断,具体如上述
- 物理内存被划分为页框(如
-
所谓物理内存划分为固定大小的页框,然后由页表保存页表项,一个页表在系统上表现为一个文件吗?
- 物理内存被划分为固定大小的页框(
Page Frame),而页表(Page Table)是操作系统用于管理虚拟地址到物理地址映射的核心数据结构 - 页表本身并不表现为文件,而是以内存中的数据结构形式存在
- 但是,当物理内存不足时,操作系统会将不活跃的物理页(页框)换出到磁盘的交换文件(
Page File/Swap Space),此时页表项中的存在位(Present Bit)同时也会被清零,标记该页不在内存中 - 访问被换出的页面时,触发缺页中断,操作系统从交换文件加载数据到新分配的物理页框,并更新页表项的存在位和物理页框号
- 物理内存被划分为固定大小的页框(
-
pagefile.sys存储的是部分不活跃的物理页(页框)的全部数据吧,而不是一个不活跃的物理页一个pagefile.sys文件?pagefile.sys是Windows系统中唯一的虚拟内存页面文件,它存储的是部分不活跃物理页(页框)的全部数据,而非每个不活跃页对应一个单独文件
-
系统中有很多进程同时在运行,虽然通过虚拟内存的分页技术和硬盘的结合,为每个进程分配了
4GB的进程地址空间(32位系统,虚拟内存),但是系统的物理内存大小可能就8GB,它是怎么够用的?- 进程启动时仅分配虚拟地址空间,物理内存的分配是在首次访问页面时触发的(通过缺页中断)
- 虚拟地址空间中大部分区域初始状态为“空闲”或“保留”,只有实际被使用的“已提交”内存才会占用物理资源
- 当物理内存不足时,操作系统会将不活跃的页面换出到硬盘的
pagefile.sys(Windows)或交换分区(Linux) - 多个进程可共享同一物理内存页
例如,Windows的DLL文件或Linux的共享库(如glibc)只需加载一次,所有调用进程共享其代码段 - 当进程尝试修改共享内存时,系统会创建该页的私有副本,避免直接冲突
声明:本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Windows 核心编程 _ 用户模式:线程同步二07/16
- ♥ Soui九07/25
- ♥ C++程序高级调试与优化_第一篇07/20
- ♥ COM组件_101/31
- ♥ 51CTO:Linux C++网络编程二08/14
- ♥ x86_64汇编学习记述二08/07