Linux内存管理(x86-32位系统)

linux内存的管理主要分为两部分,地址管理和存储设备管理。下面针对这两部分介绍一下我对内存管理的理解。

硬件地址的基本概念

  • DRAM域地址:是DRAM控制器所能访问的地址空间集合。
  • PCI总线域地址:是PCI设备所能直接访问的地址空间集合。
  • 存储器域地址:是CPU所能访问的地址空间集合。

结合下图对上面概念进行解释:

CPU访问DRAM域或PCI总线域地址空间时,都需要进行地址转换(将存储器域地址转换为相应域的地址)。例如:CPU访问DRAM域时,需要进行存储器域地址空间到DRAM域地址空间的转换(由DRAM控制器完成);CPU访问PCI总线域时,需要进行存储器域地址空间到PCI总线域地址空间的转换(由HOST主桥完成)。

在x86处理器系统中,会将DRAM域和PCI总线域映射到存储器域空间中,并且其大多数DRAM域中的地址与存储器域中的地址一一对应而且相等,而存储器域的PCI地址与PCI总线域的地址也一一对应而且相等。它们在存储器域空间的映射彼此独立,互不冲突,映射关系由BIOS提供(e820地址映射表)。

PCI设备访问DRAM域地址空间时,首先要经过HOST主桥将PCI总线域地址转换为存储器域地址,然后再由DRAM控制器将存储器域地址转换为DRAM域地址。

软件地址的基本概念

  • 逻辑地址,是一个32位长的地址。所有进程地址都使用逻辑地址。
  • 线性地址(也称为虚拟地址),是一个32位长地址,可以用来表示高达4G的地址,值的范围从0x00000000到0xffffffff。它是通过分段单元的硬件电路将逻辑地址转换为线性地址,即将逻辑地址加上一个段起始地址就得到了线性地址。在linux中,所有的段都从0x00000000开始,所以在linux下逻辑地址等于线性地址,即进程地址也是线性地址。后面我们就不再讨论逻辑地址,而都使用线性地址代表进程所使用的地址。
  • 物理地址,是通过分页单元的硬件电路将线性地址转换为物理地址。该地址就是上面所说的存储器域地址,是CPU所能访问的地址空间的集合

下面用图对上面概念进行解释:

在X86系统中,所有进程都使用的是逻辑地址,它要通过分段单元硬件电路转换为线性地址,再通过分页单元硬件电路转换为物理地址(即存储器域地址)。

分段单元的逻辑如下图所示(将逻辑地址转换为线性地址)

分页单元的逻辑如下图所示(将线性地址转换为物理地址)

地址管理

linux将线性地址空间分为user和kernel两个空间

  • USER线性地址空间,指的是可被应用层访问的线性地址空间。其大小(32位处理器) = 4G - KERNEL线性地址空间大小。
  • KERNEL线性地址空间,指的是可被内核使用的线性地址空间。其大小 = LOWMEM线性地址空间大小 + VMALLOC线性地址空间大小。
    • LOWMEM线性地址空间,它占用了KERNEL线性地址空间中的一部分。其大小 = KERNEL线性地址空间大小 - VMALLOC线性地址空间大小 。
    • LOWMEM功能,这段地址空间在启动时已做好地址映射,其映射的物理内存是连续的,并与物理内存地址一一对应。
    • VMALLOC线性地址空间,它占用了KERNEL线性地址空间中的另一部分。其大小 = (KERNEL线性地址空间大小 - 物理内存大小) > VMALLOC_RESERVE ?KERNEL线性地址空间 - 物理内存大小 : VMALLOC_RESERVE
    • VMALLOC功能,用于在内核中分配线性地址连续,但物理地址不需连续的大内存区。这段地址空间初始化时未做任何地址映射。

linux内核线性地址空间变量的含义

  • PAGE_OFFSET = __PAGE_OFFSET = CONFIG_PAGE_OFFSET:这个值是用于划分USER线性地址和KERNEL线性地址的分界点。
  • __VMALLOC_RESERVE:表示为VMALLOC线性地址空间最小应保留的空间大小,默认是128M。这个值可在系统启动时通过内核参数vmalloc来改变。
  • VMALLOC_END:VMALLOC线性地址空间的结束地址。其值 = 最大线性地址 – 其它ROM内存空间大小
  • VMALLOC_START:VMALLOC线性地址空间的起始地址。其值 = VMALLOC_END - VMALLOC线性大小(最小为VMALLOC_RESERVE)
  • VMALLOC_OFFSET:固定大小为8M,用于再LOWMEM线性地址空间和VMALLOC线性地址空间之间建立一个隔离带,防止它们互相影响。
  • MAXMEM:其值为(VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE),表示内核能够直接映射的最大RAM容量,这个值也是相对固定的(与物理内存实际的大小没有关系),因为VMALLOC_END、PAGE_OFFSET、 __VMALLOC_RESERVE是相对固定的。
  • MAXMEM_PFN:其值为PFN_DOWN(MAXMEM),表示内核能够直接管理的内存页个数。
  • MAX_ARCH_PFN:表示CPU最大可访问的内存页数。对应32位CPU,如果其开启了PAE,则MAX_ARCH_PFN=(1ULL?(36-PAGE_SHIFT))。如果未开启PAE,则MAX_ARCH_PFN=(1ULL?(32-PAGE_SHIFT))
  • max_pfn:是从bios发现的最大的能管理的内存页个数, 与实际内存大小有关,但它的大小不能超过MAX_ARCH_PFN。
    当max_pfn <= MAXMEM_PFN时说明实际的物理内存比内核能够线性映射的内存数小,此时就不需要Highmem来管理了。此时就算开启了HIGHMEM,ZONE_HIGHMEM区能够管理的内存大小也是0。
    当max_pfn > MAXMEM_PFN时说明实际的物理内存比内核能够线性映射的内存数大,这样多余的那部分物理内存就不能进行线性映射了,必须通过页表映射(即vmalloc来管理), 该物理内存应该由ZONE_HIGHMEM区来管理。而如果没有开启HIGHMEM选项,则这部分内存就丢失了,不再被管理。
  • max_low_pfn:低端内存(相对于highmem)的最大页数,这个就是ZONE_NORMAL区能管理的最大页数。
    如果实际物理内存比内核能够线性映射的内存数小,max_low_pfn = max_pfn,即所有的内存都归低端内存区管理。
    如果实际物理内存比内核能够线性映射的内存数大,max_low_pfn = MAXMEM_PFN,即低端内存区能够管理的最大值就是内核能够线性映射的最大值。
  • highmem_pages:高端内存的最大页数,这个是就是ZONE_HIGHMEM区管理的最大页数。其值为(max_fn – max_low_pfn)。

存储设备管理(即可使用物理内存空间的管理)

linux内核将物理内存空间进行功能区划分(划分时要参考地址管理中线性地址的分配),并通过page结构进行管理

  • ZONE_DMA物理内存空间,在x86体系结构上它是0~16M的内存范围。由page结构进行管理,这个区包含的页能被老设备执行DMA操作。
  • ZONE_NORMAL物理内存空间,在x86体系上它是16M~KERNEL->LOWMEM线性地址对应的内存范围。由page结构进行管理。
    (内核在启动时,就已经将上面这两个区的内存空间映射到KERNEL线性地址空间中了。所以内核不需做任何操作,就可以直接访问这些物理内存。但为了保证所访问内存页没有被其它功能使用,因此在访问内存之前,要使用get_free_page()等函数获取空闲页,并将该页标记为使用。返回的物理页不需要做任何地址映射,仅仅是将物理地址加上内核空间偏移量就获得了其线性地址)
  • ZONE_HIGHMEM物理内存空间,其大小 = 实际物理内存大小 – KERNEL->LOWMEM线性地址空间大小。由page结构进行管理,用于管理物理内存大小超过KERNEL->LOWMEM线性地址空间大小以外的物理内存。这段内存空间没有被映射到内核线性地址空间,在使用时,要通过alloc_page()分配一个page页,然后再将该页映射到线性地址空间,这样才能通过线性地址访问。内核(通常用vmalloc()函数)将HIGHMEM物理内存页映射到VMALLOC线性地址空间,因此内核可使用的HIGHMEM物理内存大小与VMALLOC线性地址空间大小有关。另外,HIGHMEM物理内存页通常被映射到USER线性地址空间。
  • ZONE_NORMAL 与ZONE_HIGHMEM主要的区别是ZONE_NORMAL中的物理内存不需要做页表映射直接用就行了,其线性地址的最大值是MAXMEM。而ZONE_HIGHMEM中的物理内存需要做页表映射才能使用,其线性地址的范围是VMALLOC_START~VMALLOC_END。所以不能做线性映射的内存都归ZONE_HIGHMEM来管理了。如果开启的HIGHMEM选项,则ZONE_HIGHMEM的大小就是剩下的物理内存,如果没开起,则这部分物理内存就无法管理了。
时间: 2024-11-05 12:20:27

Linux内存管理(x86-32位系统)的相关文章

linux内存管理浅析

[地址映射](图:左中)linux内核使用页式内存管理,应用程序给出的内存地址是虚拟地址,它需要经过若干级页表一级一级的变换,才变成真正的物理地址.想一下,地址映射还是一件很恐怖的事情.当访问一个由虚拟地址表示的内存空间时,需要先经过若干次的内存访问,得到每一级页表中用于转换的页表项(页表是存放在内存里面的),才能完成映射.也就是说,要实现一次内存访问,实际上内存被访问了N+1次(N=页表级数),并且还需要做N次加法运算.所以,地址映射必须要有硬件支持,mmu(内存管理单元)就是这个硬件.并且需

Windows内存管理和linux内存管理

windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或者页面,然后把页式虚拟地址与内存地址建立一一对应的页表:并用相应的硬件地址变换机构来解决离散地址变换问题.页式管理采用请求调页或预调页技术来实现内外存存储器的统一管理.其优点是没有外碎片,每个内碎片不超过页的大小.缺点是,程序全部装入内存,要求有相应的硬件支持.例如地址变换机构缺页中断的产生和选择淘

x86 32位机的特权保护

优先级划分.指令的权限检查和超出权限访问的异常处理等是构成特权保护的基础.本文将试图讲解为大家解决两大问题: --win32汇编中为什么找不到中断指令的应用?比如int 7ch --windows错误的'蓝屏'是从哪里来的? 保护模式下,中断或异常往往从用户代码切换到操作系统代码中执行.由于保护模式下的代码有优先级之分,因此出现从优先级低的应用程序转移到优先级高的系统代码的问题,如果优先级低的代码能够任意调用优先级高的代码,就相当于了拥有了高优先级代码的权限.为了使高优先级代码能够安全的被低优先

Linux判断CPU是32位还是64位,判断系统是32位还是64位

from:http://www.ipcpu.com/2010/08/linux-cpu-32-64/ 本文仅限于服务器CPU和Linux系统讨论,与台式电脑.笔记本无关. 32位.64位不能乱装,64的能装32位的,因为64位的CPU可以兼容32位,32位的装不了64位的.最近部署了MongoDB,系统是32位的提示会有最大文件2G的限制.还有最常见的问题32位系统不支持4G以上内存,即使打PAE效率也受影响. 1.判断CPU是32位还是64位 这个问题比较有意思,网上给出的办法都是判断了系统的

为什么32位系统最大支持4G内存??我自己悟出来了 终于 。。。。。

今天突然开窍了,想通了..... 以下是我的抽象想法: 32位系统 这个 多少位 指的是 硬件的 一次性发送过来的位数,一个字节 等于8位,内存的一个存储单元就是一个字节,即8位. 也可以这样来想这个位,就是栈中内存地址的二进制 位数,那么 32位 的意思是 栈中内存地址最大是 32个11,即: 你会发现,32位系统的 最大内存地址为:2的32次方 - 1,最小地址地址为:0-----因为计算机都是从0开始的.32个0 也是 一个内存地址. 那么32位系统的 最大寻址空间是:0 — (2的32次

sql2005性能优化(在32位系统上突破2G内存使用量的方法) .

转载自http://blog.csdn.net/soldierluo/article/details/6589743 服务器磁盘为(SAS)IBM组成RAID0+1,SQL2K5只识别4G内存,实际只占用2G内存.而使用 AWE的话,应用程序可以直接将操作系统允许的最大物理内存量保留为未分页的内存.使用 AWE 使 SQL Server 可以缓存详细信息,而不用从磁盘上的系统页面文件中读取详细信息.通过更快的数据访问提高了性能并减少了访问磁盘的频率.故决定打开SQL2K5的AWE参数,将6G的内

详解为什么32位系统只能用4G内存.

本文转自:https://www.cnblogs.com/nvd11/archive/2013/04/02/2996784.html,感谢作者的干货 既然是详解, 就从最基础的讲起了. 1. Bit(位)              Bit计算机是计算机最小的存储单位,  大家都知道计算机实质上都是用二进制数0或者1来存储数据的,  所以Bit实际上可以看成存放1个二进制数字的1个位置.             也就是说bit只有2种值, 0 或者 1, 所以1个bit能存放1个布尔类型的值(bo

百杂讲堂之为什么32位系统只能操作4g内存

百杂讲堂之为什么32位系统只能操作4g内存 计算机内存中很多的单元,每一个单元就是一个字节,一个字节有8位.每一个单元有两种状态:0和1. 所以 两个单元就有4个组合: 3个单元就有8个组合: 依次类推--: n个地址就有2的n次方组合. 32位计算机,就有32个的单元,就能控制2^32个单元,即2^32个字节,也就是2^32B,等于4GB,所以32位系统的计算机只能控制4gb的内存. 很多人也就想到了,现在有64位的系统,那么也就有2^64个单元,约等于17,179,869,184GB,oh

启动期间的内存管理之初始化过程概述----Linux内存管理(九)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDrivers Linux内存管理 在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检测到可用内存和寄存器. 而我们今天要讲的boot阶段就是系统初始化阶段使用的内存分配器. 1 前景回顾 1.1

linux内存管理---虚拟地址、逻辑地址、线性地址、物理地址的区别(一)

分析linux内存管理机制,离不了上述几个概念,在介绍上述几个概念之前,先从<深入理解linux内核>这本书中摘抄几段关于上述名词的解释: 一.<深入理解linux内核>的解释 逻辑地址(Logical Address) 包含在机器语言指令中用来指定一个操作数或一条指令的地址(有点深奥).这种寻址方式在80x86著名的分段结构中表现得尤为具体,它促使windows程序员把程序分成若干段.每个逻辑地址都由一个段和偏移量组成,偏移量指明了从段开始的地方到实际地址之间的距离. 线性地址(