物理内存低于896M各个区到底是怎么映射的

简介:

在Linux内核空间里,有三种内存区,ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM。

在64位系统上,HIGHMEM是不存在的,只有在32位系统上才会有。

在32位系统上,高于896M的物理内存称为高端内存。

内核地址空间为 3G-4G。

3G ~ 3G+896M为直接映射区,也就是说物理地址和内核虚拟地址只差3G的偏移量,比如说,内核中某个变量地址为3G+24M,那么这个变量所在的物理地址必然是24M。

内核还剩下128M的地址空间,这些是干什么用的呢?因为物理地址可能高于1G,高于1G的地方在内核里无法直接寻址,那怎么办的,这128M就是用来映射高于896M部分的内存的。举个例子,

内核里某个变量的地址是3G+1000M,那么这个变量的物理地址一般不会是1000M,当然有这个可能,因为1000M也位于高端内存。内核需要为这128M空间建立映射关系,128M映射896M~64G的部分(最多64G,开启PAE)。

这128M又分成几个区:

低于896M的部分称为直接映射区,后面分为VMALLOC区,永久映射区,固定映射区。

#define VMALLOC_OFFSET (8*1024*1024) //VMALLOC区与直接映射区的间隙,为了捕捉越界

范围是VMALLOC_START到VMALLOC_END,中间的4K是为了把分配的每段内存隔开,就像用户层的malloc,中间会有间隙。

这个VMALLOC分配内存时,会把地址映射到这个区域,举个例子,假如你用vmalloc得到了1M内存,物理地址(假设连续,实际不一定)为22G~22G+1M,返回给你的地址有可能是920M~921M。kmalloc与vmalloc的区别之一就是kmalloc会在低端内存申请。

后面的PKMAP区和FIXMAP区用法是这样的,你得到了一个高端内存的page,需要在内核里读写,但是内核不能直接操作page,需要地址,这样你调用kmap或者kmap_atomic,会把这个page映射到这两个区。当然加入这个page来自低端内存,直接返回page_address()的结果。

有一个问题一直很困扰我,假入内存不到896M呢?实际上内存不到896M,照样可以使用vmalloc。

先来看个例子

 
  1. #include <linux/init.h>  
  2. #include <linux/module.h>  
  3. #include <linux/vmalloc.h>  
  4. static int hello_init(void)  
  5. {  
  6.         char *test;  
  7.         char *test1;  
  8.         test = vmalloc(8);  
  9.         test1 = kmalloc(8,0);  
  10.         printk(KERN_ALERT "%x,%d\n",test,(unsigned int)test/(1024*1024));  
  11.         printk(KERN_ALERT "%x,%d\n",test1,(unsigned int)test1/(1024*1024));  
  12.         vfree(test);  
  13.         kfree(test1);  
  14.         return 0;  
  15. }  
  16. static void hello_exit(void)  
  17. {  
  18.         printk(KERN_ALERT "Goodbye,cruel world!\n");  
  19. }  
  20. module_init(hello_init);  
  21. module_exit(hello_exit); 

内存256M:

内存512M:

 

内存1024M:

 

可见VMALLOC区不一定是在896M+8M到896M+8M+128M。

kmalloc返回的地址都在物理内存范围内,而vmalloc返回的地址就不一样了。我们再看上面各个区的分布图,发现有个high_memory,其实这是个变量,

上面是在物理内存为256的情况下打印high_memory,(除以1024*1024),可见这个high_memory是根据物理内存算出来的,具体代码如下

 
  1. #ifdef CONFIG_HIGHMEM  
  2.         highstart_pfn = highend_pfn = max_pfn;  
  3.         if (max_pfn > max_low_pfn)  
  4.                 highstart_pfn = max_low_pfn;  
  5.         e820_register_active_regions(0, 0, highend_pfn);  
  6.         sparse_memory_present_with_active_regions(0);  
  7.         printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",  
  8.                 pages_to_mb(highend_pfn - highstart_pfn));  
  9.         num_physpages = highend_pfn;  
  10.           high_memory = (void *) __va(highstart_pfn * PAGE_SIZE-1)+1;   
  11. #else  
  12.         e820_register_active_regions(0, 0, max_low_pfn);  
  13.         sparse_memory_present_with_active_regions(0);  
  14.         num_physpages = max_low_pfn;  
  15.          high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1)+1;   
  16. #endif  

VMALLOC_START在high_memory后面8M开始,一般应该是高于物理内存的。

我们来理清几个问题:

低于896M的物理内存与虚拟内存在内核空间里是一一对应的,这句话是有问题的,需要分情况说。

如果总得物理内存低于896M,假设为A,对于内核中的一个地址,如果小于A那么这个地址与物理地址只差一个偏移量,如果大于A,那么肯定位于VMALLOC区。如果一个物理地址为X的页被内存使用,即使X小于896,它对应的虚拟地址也有可能不是3G+896。

越写越乱,先写到这吧。



本文转自nxlhero 51CTO博客,原文链接:http://blog.51cto.com/nxlhero/711805,如需转载请自行联系原作者

相关文章
|
3月前
|
Linux
内存学习(五):物理内存组织
内存学习(五):物理内存组织
177 0
|
3月前
|
缓存
内存学习(三):物理地址空间
内存学习(三):物理地址空间
62 0
|
3月前
|
缓存 Linux C语言
Linux内存管理宏观篇(四)物理内存:物理内存管理区
Linux内存管理宏观篇(四)物理内存:物理内存管理区
55 1
|
3月前
|
存储 缓存 Unix
内存学习(一):物理地址空间内存概述
内存学习(一):物理地址空间内存概述
38 0
|
22天前
|
存储 缓存 安全
深入理解内存映射:mmap映射的背后原理以及和共享内存的差异
深入理解内存映射:mmap映射的背后原理以及和共享内存的差异
51 0
|
28天前
|
存储 算法 内存技术
深入理解操作系统内存管理:从虚拟内存到物理内存
【2月更文挑战第30天】 在现代计算机系统中,操作系统的内存管理是确保系统高效稳定运行的关键组成部分。本文将深入探讨操作系统内存管理的复杂世界,特别是虚拟内存和物理内存之间的关联与转换机制。通过分析分页系统的工作原理、虚拟地址空间的结构以及页面置换算法,文章旨在为读者提供一个清晰的框架,以理解内存管理在操作系统中的重要性和实现细节。
|
1月前
|
存储 缓存 Linux
|
2月前
|
SQL Java 数据库连接
Flink内存问题之超出物理内存如何解决
Apache Flink是由Apache软件基金会开发的开源流处理框架,其核心是用Java和Scala编写的分布式流数据流引擎。本合集提供有关Apache Flink相关技术、使用技巧和最佳实践的资源。
|
3月前
|
C语言 芯片
获取物理内存容量
获取物理内存容量
38 0
|
3月前
|
搜索推荐 Linux
内存学习(二):物理地址空间虚拟地址空间布局
内存学习(二):物理地址空间虚拟地址空间布局
75 0