我所理解的high memory
来源:互联网 发布:淘宝实名认证 编辑:程序博客网 时间:2024/06/05 18:39
关于Linux 中high memory,网上已经有好多人讲解,在这里把我收集到的资料归纳总结一下,同时加入一些自己的理解,如有不正确之处欢迎指正。
一: 为什么需要high memory
32位的CPU,最大寻址范围2^32-1, 也就是虚拟内存空间的范围为0~4G。 Linux一般吧0~3G划分为用户地址空间,3G到4G为内核地址空间。
图1: 用户和内核地址空间分布
最高的1GB虚拟空间由所有进程和内核共享,因此内核最多寻址1G的虚拟地址空间。如果物理内存超过1G,内核该如何映射呢?
Linux采取的策略内核空间的前“896M”(注:896M是一个笼统的概念,详细参照第二节)采用固定映射(也可以称为静态映射,直接映射),这部分页表是固定的,虚拟地址 - PAGE_OFFSET = 物理地址(PAGE_OFFSET 一般为3G,0xC0000000),这部分的映射是系统刚刚初始化的时候就建立的,这段物理内存被称为Low Memory。而虚拟地址空间的后“128M”,也就是3G+“896M” ~ 4G-1部分采用动态映射。这样如果物理内存大于1G,通过更新页表就可以被映射到了。(试想如果1G的虚拟地址空间全部采用固定映射,那超过1G的物理内存将无法被内核访问,对不对?)所以超过“896M”的物理内存就称为High Memory。
那如果内存只有1G,是不是可以全部采用固定映射了呢?答案还是No!这是因为内核除了访问内存,还需要访问很多IO设备比如硬件寄存器,片上内存等,所以1G的虚拟空间不可以全部映射到1G的物理内存,仍然需要预留部分空间给这些IO资源(一般ioremap就是用来做这种 映射的)。内核提供了动态映射High Memory的方法,比如kmap, vmalloc。由此大家可以看到High Memory对于系统的物理内存比较大时是必要的。
由此我们可以看出high memory的一些结论如下:
1. High Memory 是指物理内存,可以使内核地址空间映射到高端物理内存,比如大于1G的物理内存这个时候就可以被映射到, 或者硬件寄存器的地址,like 0xdxxxxxxxx,0xcxxxxxxx);
2. High Memory 跟Low Memory一样都被内核管理,都有对应的page结果,都可以被kernel/user 分配,他们的区别是High Memory没有固定的内核虚拟空间与之对应。 High Memory 是内核区间固定映射和动态映射的分界。
3. 如果物理内存较小比如小于“896M”,High Memory是可以没有的;64位系统下不会有High Memory,因为64的虚拟地址空间非常大,物理内存可以被全部固定映射。
二: High Memory VS 最高端的“128M”内核虚拟地址:
以i386中一个典型的内存分布为例(物理内存大于“896M”):内核所能自由访问的物理内存为MAXMEM(有固定映射的内存区) 如下定义:
图2: Linux 虚拟内存空间分布
#define VMALLOC_OFFSET (8 * 1024 * 1024)
#define VMALLOC_START ((unsigned long)high_memory +VMALLOC_OFFSET)
#ifdef CONFIG_X86_PAE
#define LAST_PKMAP 512
#else
#define LAST_PKMAP 1024
#endif
#define PKMAP_BASE((FIXADDR_BOOT_START - PAGE_SIZE * (LAST_PKMAP + 1)) & PMD_MASK)
#ifdef CONFIG_HIGHMEM
# define VMALLOC_END (PKMAP_BASE - 2 * PAGE_SIZE)
#else
# define VMALLOC_END (FIXADDR_START - 2 * PAGE_SIZE)
#endif
#define MAXMEM (VMALLOC_END - PAGE_OFFSET -__VMALLOC_RESERVE)
可以看到MAXMEM是由VMALLOC_END,PAGE_OFFSET和__VMALLOC_RESERVE决定的。PAGE_OFFSET是0xC0000000。
从以上的定义可以看到,从0xFFFFFFFF的最高地址往下,有FIXADDR固定映射区(主要用在boot阶段用来永久性映射一些物理地址固定的数据结构或者硬件地址(比如ACPI表,APIC地址,等等),PKMAP区(kernel用来临时建立映射来访问物理页用的,可用的地址空间也比较小,4M)和VMALLOC区(128M -8M,8M用来cache kernel 指针错误)。在这三个区域以下是kernel可以使用自由访问的物理内存空间。可以通过下图看到大体的内核1G虚拟地址空间的分布概况:
由此可以看到我们之前所说896M/128M 其实是一个比较笼统的概念,笔者猜测因为vmalloc area 占据了这部分区间的绝大部分,而__VMALLOC_RESERVEdefault 为128M,由此得来这个划分。
现在再以ARM 为例,default vmalloc area 被定义为240M:
#define VMALLOC_END 0xff000000UL
static void * __initdata vmalloc_min=
(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
而vmalloc_reserve可以通过cmd line 在early_param("vmalloc", early_vmalloc)来配置,如下vmalloc_reserve 最小为16M,最大为VMALLOC_END - (PAGE_OFFSET + 32M). 其中vmalloc_reserve= vmalloc_size + VMALLOC_OFFSET(8M) 。Kernel 将那些与vmalloc area 范围有重叠的memory bank分隔开来,Highmemory的start即被定义为vmalloc_min所对应的物理地址。
ARM 体系架构中PKMAP_BASE 不同于x86,
#define PKMAP_BASE (PAGE_OFFSET - PMD_SIZE)
从VMALLOC_END 向上到0xFFFFFFFF的区间:
Fixmap 区间的范围是0xfff00000~0xffffdffff (Addresses provided by fix_to_virt() will be located here)。
其余的区间要不是特殊用途,要不是reserve的区间。具体分布可以参照Memory.txt @Documentation\arm\
由此我们可以看到ARM中的highmemory 的起始地址可以更加自由的配置,因为“896M”的分界对ARM而言就更笼统了。
再来说一下vmalloc区间,这段连续的虚拟地址空间,不论是否有highmemory都是存在的,它的存在使得连续的虚拟地址空间可以映射到非连续的物理内存,只要通过更新页表就可以做到,这和用户态的虚拟内存映射采用了同样这种方法。这在没有大段连续的空闲物理地址时,是非常重要的。
- 我所理解的high memory
- 我所理解的PKI
- 我所理解的抽象
- 我所理解的OpenSocial
- 我所理解的IOCP
- 我所理解的Rails
- 我所理解的爱情
- 我所理解的团队精神
- 我所理解的HBase
- 我所理解的生活
- 我所理解的JSON
- 我所理解的生活
- 我所理解的syslog
- 我所理解的KMP
- 我所理解的抽象
- 我所理解的马
- 我所理解的service
- 我所理解的注入
- 高仿京东商城源码大放送
- hdu _p1018 BigNumber
- A+B Coming 1720
- 初生程序员是头牛
- 解剖cloudfoundry(三) --bosh_cli的安装
- 我所理解的high memory
- 【Linux】虚拟机Ubuntu系统访问主机windows共享文件夹文件类型出错
- javax.persistence.EntityManager.getMetamodel()Ljavax/persistence/metamodel/Metamodel
- http status 汇总
- iptables禁止端口和开放端口
- C# 读取 timestamp 时间戳 值为byte[] 类型时,需要转换成 16进制的字符串 和 数据库中的时间戳值进行比对
- JQUERY EasyUI datagrid重新加载传参
- javascript删除option选项的多种方法总结
- 《Linux启动过程分析》之区别Initramfs与initrd