高端内存是指物理地址大于 896M 的内存。对于这样的内存,无法在“内核直接映射空间”进行映射。

为什么?

  因为“内核直接映射空间”最多只能从 3G 到 4G,只能直接映射 1G 物理内存,对于大于 1G 的物理内存,无能为力

  实际上,“内核直接映射空间”也达不到 1G, 还得留点线性空间给“内核动态映射空间” 呢。

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

  对于高端内存,可以通过 alloc_page() 或者其它函数获得对应的 page,但是要想访问实际物理内存,还得把 page 转为线性地址才行(为什么?想想 MMU 是如何访问物理内存的),也就是说,我们需要为高端内存对应的 page 找一个线性空间,这个过程称为高端内存映射。

高端内存映射有三种方式:

1、映射到“内核动态映射空间”

  这种方式很简单,因为通过 vmalloc() ,在“内核动态映射空间”申请内存的时候,就可能从高端内存获得页面(参看 vmalloc 的实现),因此说高端内存有可能映射到“内核动态映射空间” 中

2、永久内核映射

  如果是通过 alloc_page() 获得了高端内存对应的 page,如何给它找个线性空间?

  内核专门为此留出一块线性空间,从 PKMAP_BASE 到 FIXADDR_START ,用于映射高端内存。在 2.4 内核上,这个地址范围是 4G-8M 到 4G-4M 之间。这个空间起叫“内核永久映射空间”或者“永久内核映射空间”

  这个空间和其它空间使用同样的页目录表,对于内核来说,就是 swapper_pg_dir,对普通进程来说,通过 CR3 寄存器指向。

  通常情况下,这个空间是 4M 大小,因此仅仅需要一个页表即可,内核通过来 pkmap_page_table 寻找这个页表。

  通过 kmap(), 可以把一个 page 映射到这个空间来

  由于这个空间是 4M 大小,最多能同时映射 1024 个 page。因此,对于不使用的的 page,应该及时从这个空间释放掉(也除映射关就是解系),通过 kunmap() ,可以把一个 page 对应的线性地址从这个空间释放出来。

3、临时映射

  内核在 FIXADDR_START 到 FIXADDR_TOP 之间保留了一些线性空间用于特殊需求。这个空间称为“固定映射空间

  在这个空间中,有一部分用于高端内存的临时映射。

  这块空间具有如下特点:

  1、 每个 CPU 占用一块空间

  2、 在每个 CPU 占用的那块空间中,又分为多个小空间,每个小空间大小是 1 个 page,每个小空间用于一个目的,这些目的定义在 kmap_types.h 中的 km_type 中。

  当要进行一次临时映射的时候,需要指定映射的目的,根据映射目的,可以找到对应的小空间,然后把这个空间的地址作为映射地址。这意味着一次临时映射会导致以前的映射被覆盖。

  通过 kmap_atomic() 可实现临时映射。

下图简单简单表达如何对高端内存进行映射

Linux内存线性地址空间大小为4GB,分为2个部分:用户空间部分(通常是3G)和内核空间部分(通常是1G)。在此我们主要关注内核地址空间部分。

内核通过内核页全局目录来管理所有的物理内存,由于线性地址前3G空间为用户使用,内核页全局目录前768项(刚好3G)除0、1两项外全部为0,后256项(1G)用来管理所有的物理内存。内核页全局目录在编译时静态地定义为swapper_pg_dir数组,该数组从物理内存地址0x101000处开始存放。

由图可见,内核线性地址空间部分从PAGE_OFFSET(通常定义为3G)开始,为了将内核装入内存,从PAGE_OFFSET开始8M线性地址用来映射内核所在的物理内存地址(也可以说是内核所在虚拟地址是从PAGE_OFFSET开始的);接下来是mem_map数组,mem_map的起始线性地址与体系结构相关,比如对于UMA结构,由于从PAGE_OFFSET开始16M线性地址空间对应的16M物理地址空间是DMA区,mem_map数组通常开始于PAGE_OFFSET+16M的线性地址;从PAGE_OFFSET开始到VMALLOC_START – VMALLOC_OFFSET的线性地址空间直接映射到物理内存空间(一一对应影射,物理地址<==>线性地址-PAGE_OFFSET),这段区域的大小和机器实际拥有的物理内存大小有关,这儿VMALLOC_OFFSET在X86上为8M,主要用来防止越界错误;在内存比较小的系统上,余下的线性地址空间(还要再减去空白区即VMALLOC_OFFSET)被vmalloc()函数用来把不连续的物理地址空间映射到连续的线性地址空间上,在内存比较大的系统上,vmalloc()使用从VMALLOC_START到VMALLOC_END(也即PKMAP_BASE减去2页的空白页大小PAGE_SIZE(解释VMALLOC_END))的线性地址空间,此时余下的线性地址空间(还要再减去2页的空白区即VMALLOC_OFFSET)又可以分成2部分:第一部分从PKMAP_BASE到FIXADDR_START用来由kmap()函数来建立永久映射高端内存;第二部分,从FIXADDR_START到FIXADDR_TOP,这是一个固定大小的临时映射线性地址空间,(引用:Fixed virtual addresses are needed for subsystems that need to know the virtual address at compile time such as the APIC),在X86体系结构上,FIXADDR_TOP被静态定义为0xFFFFE000,此时这个固定大小空间结束于整个线性地址空间最后4K前面,该固定大小空间大小是在编译时计算出来并存储在__FIXADDR_SIZE变量中。

正是由于vmalloc()使用区、kmap()使用区及固定大小区(kmap_atomic()使用区)的存在才使ZONE_NORMAL区大小受到限制,由于内核在运行时需要这些函数,因此在线性地址空间中至少要VMALLOC_RESERVE大小的空间。VMALLOC_RESERVE的大小与体系结构相关,在X86上,VMALLOC_RESERVE定义为128M,这就是为什么ZONE_NORMAL大小通常是16M到896M的原因。

Linux内存管理-高端内存(一)相关推荐

  1. Linux 内存管理 —— 高端内存

    文章目录 0. 参考资料 1.1 进程线性地址空间划分 1.2 x86 体系架构下的两种硬件约束 1.3 应对硬件约束的方法 0. 参考资料 https://www.zhihu.com/questio ...

  2. 详谈Linux系统《高端内存和低端内存》

    高端内存是Linux中一个重要的概念,初涉Linux时曾经对这个概念非常迷惑.实际上这个概念比较简单,理解这个概念,需要追溯一下Linux的内存管理. 从前,CPU的地址总线只有32位.32的地址总线 ...

  3. 【Linux】Linux的内核空间(低端内存、高端内存)

    内核也是程序,也应该具有自己的虚存空间,但是作为一种为用户程序服务的程序,内核空间有它自己的特点. 内核空间与用户空间的关系 在一个32位系统中,一个程序的虚拟空间最大可以是4GB,那么最直接的做法就 ...

  4. Linux内存管理之高端内存映射

    一:引子 我们在前面分析过,在linux内存管理中,内核使用3G->4G的地址空间,总共1G的大小.而且有一部份用来做非连续空间的物理映射(vmalloc).除掉这部份空间之外,只留下896M大 ...

  5. Linux内存管理:内存描述之高端内存

    <Linux内存管理:内存描述之内存节点node> <Linux内存管理:内存描述之内存区域zone> <Linux内存管理:内存描述之内存页面page> < ...

  6. linux内核1G虚拟地址空间的映射规则以及什么是高端内存?

    前面我们讲了,在32位linux内核里,内核地址空间是0xc0000000~0xffffffff, 大小1G:内核地址空间是0x00000000~0xbfffffff,大小3G.当内核代码访问内存时, ...

  7. 高端内存——永久映射区(permanet kernel mappings)

    闲着无聊,把一些东西写下来给大家分享下吧,有什么不对的,欢迎质疑 注:本文提及的物理地址空间可以理解为就是物理 内存 ,但是在某些情况下,把他们理解为物理内存是不对的. 本文讨论的环境是 NON-PA ...

  8. linux内存管理 (四) 3 内存管理机制 第一阶段 迈向 第二阶段的过程

    第一阶段是个时间点 : 基本堆栈建立完成 第二阶段是个时间点 : bootmem 完成建立第二阶段到 第三阶段 是个过程, 该过程中 基本堆栈管理 消亡, bootmem 完成建立 详细过程解读 迈向 ...

  9. 计算机内存 管理,试析计算机内存的优化及管理

    摘 要:现如今,计算机设备已经成为人们生活中必不可少的必需品.计算机设备的构成部分主要包括硬件设备和软件设备两大类.计算机硬件系统包含的内容相对较多,其中典型性较强,重要性较大的就是内存.计算机设备研 ...

  10. linux 内核高端内存意义,Linux内核高端内存管理

    原先一直都对Linux高端内存的管理认识模模糊糊的,可能主要是初次接触Linux kernel 是0.11版吧,当初的内存设计是16M,Linus对拥有32M的内存都是觊觎万分,1G内存恐怕是天方夜谭 ...

最新文章

  1. Spark MLlib 机器学习
  2. Java Review - 并发编程_前置知识二
  3. 第一章:The Missing Code Library--2.合法化输入
  4. 游戏上线... 记录下...
  5. java对mysql读写权限设置_Java学习笔记——MySQL开放3306接口与设置用户权限
  6. 类的继承 设计模式
  7. UVM序列篇之一:新手上路
  8. Java常用到的快捷键
  9. ISO27001信息安全管理体系
  10. 零基础入门微信小程序开发 (2020 版)
  11. ERP是属于系统还是软件?
  12. 1寸、小2寸、2寸证件照片是多大尺寸?
  13. poi合并docx文档
  14. ZigBee网络数据传递流程_基于ZigBee远程通信的水质监测系统设计
  15. P1413 坚果保龄球
  16. 将视频转换成一帧帧的图片
  17. 如何在Word,excel 中打钩和打叉?
  18. 不怕加班狗有情绪,就怕加班狗有“武器”
  19. [GPGPU]图形处理单元上的通用计算
  20. 力扣(leetcode)[118. 杨辉三角] 简单

热门文章

  1. 再学 GDI+[25]: TGPPen - 宽度、颜色与线帽
  2. 简说JAVA8引入函数式的问题
  3. 数组遍历——Vue.js
  4. linux系统主要常见目录结构
  5. nginx limit_rate突然限速失败
  6. ASIHTTPRequest 简单应用
  7. jQuery 之正则表达式篇
  8. 《天气一点通》隐私策略
  9. this.blur()
  10. javascript的indexOf忽略大小写