内存管理——高端内存

作者:文松
链接:https://www.zhihu.com/question/280526042/answer/1615449221
来源:知乎

 

一、高端内存的由来(为什么需要高端内存)

在32位地址时代,最大可寻址0xFFFFFFFF,即4GB,因此虚拟地址空间有4GB,通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间,即Linux内核虚拟地址空间只有1G。

32位地址空间

实际的计算机体系结构有硬件的限制,这约束了页框的使用方式,其中,Linux内核必须处理x86体系结构的两种硬件约束:

  • ISA总线的直接内存存取(DMA)处理器有一个严格的限制:它们只能对RAM的前16MB地址进行寻址。
  • 在具有大容量RAM的现代32位计算机中,CPU不能直接访问所有的物理内存,因为现行地址大小太小。

为了应对这种限制,对于x86机器,Linux内核将内存区域又被分为了3个管理区(zone)。

区域
ZONE_DMA低于16MB的内存空间
ZONE_NORMAL16MB~895MB
ZONE_HIGHMEM896MB~物理内存结束

在内核或应用程序访问内存时,所操作的内存地址都为虚拟地址,而对应到真正的物理内存地址,需要地址一对一的映射。对于应用程序,虚拟地址到物理地址的转换需要MMU,而对于内核前两个管理区的内存空间被直接映射到虚拟地址空间中。

对于内核,直接映射时虚拟地址0xc0000003对应的物理地址为0x00000003,0xc0000004对应的物理地址为0x00000004。虚拟地址与物理地址有如下的对应关系:

物理地址 = 虚拟地址 – 0xC0000000

在Linux内核中,有虚拟地址向物理地址转换的宏:

__virt_to_phys

也是直接通过上面的对应关系计算而来~

如果按照上面所说的采用直接映射的方式,将内核1G的地址空间全部直接映射,就会发现内核只能访问1GB的物理内存,但是实际上我们的物理内存,往往是8G、16G,甚至更高,那么其他空间内核将无法访问和管控。所以必须要有一种灵活的方式,既减少开销,同时又让内核能够访问全部的物理内存,Linux高端内存十分必要。

Linux 规定“内核直接映射空间” 最多映射 896M 物理内存~

高端内存就是帮助我们访问除了直接映射的896MB物理内存之外的其他内存空间。

二、实现方式

内核是如何借助128MB高端内存地址空间是如何实现访问可以所有物理内存呢?

在《深入理解LINUX内核》中介绍了,内核可以采用三种不同的机制将页框映射到高端内存,分别叫做:

  1. 永久内存映射
  2. 临时内存映射
  3. 非连续内存分配

当内核想访问高于896MB物理地址内存时,从0xF8000000 ~ 0xFFFFFFFF地址空间范围内找一段相应大小空闲的虚拟地址空间,借用一会。

借用这段虚拟地址空间,建立映射到想访问的那段物理内存(即填充内核PTE页面表),临时用一会,用完后归还。这样别人也可以借用这段地址空间访问其他物理内存,实现了使用有限的地址空间,访问所有所有物理内存。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

@Swee Neil

 的回答已经把core concept介绍清楚了,我这边补充一些内容。

要理解high memory是要解决什么问题,首先要了解下内核地址转换的方式。在内核中我们往往要频繁地进行虚拟/物理地址操作,在这种情况下,快速高效的virtual to physical转换就很重要。可如果按照多级页表path walk去查找,内存访问开销就比较大,因此一种简单的"fix-mapping"思路是:将0xC0000000-0xFFFFFFFF的虚拟地址直接映射到0x00000000-0x3FFFFFFF,也就是将最高的1G地址全部映射到最低的1G,这样虚拟地址与物理地址之间就有固定的3G offset,每当遇到一个内核中的符号,我们需要得到其物理地址时,直接减去3G即可。

有人可能会问,那0-3G的比较低的那些虚拟地址怎么转换呢?答案是不用,也就是内核自己不使用0-3G的虚拟地址(除非是处理syscall)。

上述这种简单粗暴的处理方式很方便理解,效率也比较高(只需要简单的减法操作),但也有自己的局限性。在32位处理器下,按照经典用户态与内核3:1的划分比例,内核能够使用的虚拟地址只有1G大,按照固定offset的映射方式,这意味着内核能够使用的物理地址大小也只有1G。但...随着内核越来越复杂,各种数据结构对内存的需求也越来越高,比如用来物理页的page结构体,仅仅在其上增加一个12字节的reverse mapping管理结构,就会使得page总体占用的内存增高400KB,将近96个物理页大小[1];即便内存技术的发展使得高于4G的内存变得十分常见,受限于32位系统与这种fix-mapping,内核可用的物理内存大小仍然被死死地限制在1G。

以上,算是对high memory要解决问题的背景介绍。通俗地讲,"high memory"要解决的是32位下虚拟地址空间不足带来的问题(而显然,对64位系统这个问题就不存在了)。实际上在很早以前这个问题就在lwn上讨论过了[2] ,在当时已经有一些临时的方法去规避这个问题,比如重新划分用户/内核的地址空间比例,变为2.5:1.5等等,但在特定场景下(比如用户态使用的内存非常非常多)会使得用户态运行效率降低,同时带来一些非对其问题,因此也不是一个很好的办法。

怎么解决呢?

如 

@Swee Neil

 所提到的,我们可以把这1G,划分成两部分,一部分用来fix-mapping,一部分用来dynamic-mapping。以x86为例,实际中的做法是,0xC0000000-0xF7FFFFFF的896MB用作fix-mapping,0xF8000000-0xFFFFFFFF的128MB用作dynamic-mapping,前者仍然对应于物理地址的0x00000000-0x37FFFFFF(只不过部分要优先分配给DMA);后者就是所谓的high memory。当然,high memory也有自己的缺点,就是效率比较低(既然是动态的,就绕不开重映射、pte操作等等)。

实际上high memory还被划分为了3个区域[3],一部分用于vmalloc分配虚拟地址上连续的内存,一部分用于较长期的动态映射(persistent kernel mappings),还有一部分用于编译时可以直接分配物理地址的高端固定映射(fixmaps):

x86_32的memlayout

来到64位系统,这个问题天然就不存在,因此在64位系统的memlayout[3]中就没有high memory,但vmalloc仍然是内核的一个重要部分,因此memlayout中仍然有这一部分:

x86_64的memlayout

参考

  1. ^Kernel development LWN - Kernel
  2. ^Virtual Memory I: the problem Virtual Memory I: the problem [LWN.net]
  3. ^abMauerer, W. (2010). Professional Linux Kernel Architecture. Somerset: Wiley.
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 第一章 Linux底层分段分页机制 5 1.1 基于x86的Linux分段机制 5 1.2 基于x86的Linux分页机制 7 1.2.1 页全局目录和页表 8 1.2.2 线性地址到物理地址 10 1.2.3 线性地址字段处理 13 1.2.4 页表处理 15 1.3 扩展分页与联想存储器 20 1.4 Linux内存布局 21 1.5 内核空间和用户空间 23 1.5.1 初始化临时内核页表 24 1.5.2 永久内核页表的初始化 32 1.5.3 第一次进入用户空间 41 1.5.4 内核映射机制实例 44 1.6 固定映射的线性地址 48 1.7 高端内存内核映射 50 1.8.1 永久内存映射 50 1.8.2 临时内核映射 55 第二章 内核级内存管理系统 58 2.1 Linux页面管理 58 2.1.1 NUMA架构 61 2.1.2 内存管理区 62 2.2 伙伴系统算法 65 2.2.1 数据结构 66 2.2.2 块分配 67 2.2.3 块释放 69 2.3 Linux页面级内存管理 72 2.3.1 分配一组页面 73 2.3.2 释放一组页面 80 2.4 每CPU页面高速缓存 81 2.4.1 数据结构 81 2.4.2 通过每CPU 页高速缓存分配页面 82 2.4.3 释放页面到每CPU 页面高速缓存 83 2.5 slab分配器 85 2.5.1 数据结构 86 2.5.2 分配/释放slab页面 92 2.5.3 增加slab数据结构 93 2.5.4 高速缓存内存布局 94 2.5.5 slab着色 95 2.5.6 分配slab对象 96 2.5.7 释放Slab对象 100 2.5.8 通用对象 102 2.5.9 内存池 103 2.6 非连续内存区 104 2.6.1 高端内存区回顾 105 2.6.2 非连续内存区的描述符 106 2.6.3 分配非连续内存区 109 2.6.4 释放非连续内存区 113 第三章 进程的地址空间 117 3.1 用户态内存分配 117 3.1.1 mm_struct数据结构 118 3.1.2 内核线程的内存描述符 122 3.2 线性区的数据结构 123 3.2.1 线性区数据结构 123 3.2.2 红-黑树算法 126 3.2.3 线性区访问权限 128 3.3 线性区的底层处理 130 3.3.1 查找给定地址的最邻近区 131 3.3.2 查找一个与给定的地址区间相重叠的线性区 135 3.3.3 查找一个空闲的地址区间 135 3.3.4 向内存描述符链表中插入一个线性区 137 3.4 分配线性地址区间 141 3.5 释放线性地址区间 151 3.5.1 do_munmap()函数 151 3.5.2 split_vma()函数 153 3.5.3 unmap_region()函数 155 3.6 创建和删除进程的地址空间 156 3.6.1 创建进程的地址空间 156 3.6.2 删除进程的地址空间 175 3.6.3 内核线程1号的地址空间 176 3.7 堆的管理 178 第四章 磁盘文件内存映射 182 4.1 内存映射的数据结构 182 4.2 内存映射的创建 184 4.3 内存映射的请求调页 194 4.4 刷新内存映射的脏页 203 4.5 非线性内存映射 210 第五章 页面的回收 215 5.1 页框回收概念 215 5.1.1 选择目标页 216 5.1.2 PFRA设计 217 5.2 反向映射技术 218 5.2.1 匿名页的反向映射 220 5.2.2 优先搜索树 226 5.2.3 映射页的反向映射 231 5.3 PFRA实现 235 5.3.1 最近最少使用(LRU)链表 236 5.3.2 内存紧缺回收 242 5.3.3 回收磁盘高速缓存的页 267 5.3.4 周期回收 273 5.3.5 内存不足删除程序 283 第六章 交换机制 289 6.1 交换区数据结构 289 6.1.1 创建交换区 290 6.1.2 交换区描述符 291 6.1.3 换出页标识符 293 6.2 激活和禁用交换区 295 6.2.1 sys_swapon()系统调用 296 6.2.2 sys_swapoff()系统调用 304 6.2.3 try_to_unuse()函数 308 6.3 分配和释放页槽 313 6.3.1 scan_swap_map()函数 313 6.3.2 get_swap_page()函数 316 6.3.3 swap_free()函数 318 6.4 页面的换入换出 320 6.4.1 交换高速缓存 320 6.4.2 换出页 323 6.4.3 换入页 329 第七章 缺页异常处理程序 335 7.1 总体流程 335 7.2 vma以外的错误地址 341 7.3 vma内的错误地址 346 7.3.1 handle_mm_fault()函数 348 7.3.2 请求调页 352 7.3.3 写时复制 358 7.4 处理非连续内存区访问 364
Windows内存管理的最小单元是一个内存页,通常是4KB。这种虚拟内存管理方式适合用于管理大型的对象数组或大型的结构数组,并提供了丰富的内存管理接口,可以更加精确地控制内存数据。内存分页的主要目的是实现虚拟内存,从而提高系统的内存利用率。当物理内存不足时,不常用的页面可以被换出到磁盘上,并释放物理内存,以为正在执行的进程提供足够的内存空间。此外,内存分页还可以使操作系统更加灵活地管理内存,实现内存保护和共享等功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [windows内存管理操作](https://blog.csdn.net/jj6666djdbbd/article/details/127738751)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Windows管理内存的3种方式——堆、虚拟内存、共享内存](https://blog.csdn.net/Tandy12356_/article/details/130676798)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值