内核中的物理内存分配函数kernelapi

2016-01-29 17:35 19 1 收藏

内核中的物理内存分配函数kernelapi,内核中的物理内存分配函数kernel api

【 tulaoshi.com - Linux 】

在网上查资料时看到几篇介绍 linux driver 编写的文章,其中提到 kmalloc()与 __get_free_page()返回地址的问题,我们都知道 kmalloc() 与 __get_free_page() 分配的是物理内存,但它返回的到底是什么?那几篇关于驱动编写的文章中提到申请的是物理地址,返回的依然是物理地址。但有一篇文章中,作者

对此提出了质疑,但没有给出答案。这也就是我写这篇笔记的原因。在找答案的同时也将 linux kernel 分配物理内存的流程做了下分析。这仅是篇笔记,写的比较乱。自己能看懂就行了。

这里只分析分配连续物理地址的函数。对于 vmalloc() 这种分配非连续物理地址的函数不在本记录范围之内。

1、kmalloc() 分配连续的物理地址,用于小内存分配。

2、__get_free_page() 分配连续的物理地址,用于整页分配。

至于为什么说以上函数分配的是连续的物理地址和返回的到底是物理地址还是虚拟地址,下面的记录会做出解释。

kmalloc() 函数本身是基于 slab 实现的。slab 是为分配小内存提供的一种高效机制。但 slab 这种分配机制又不是独立的,它本身也是在页分配器的基础上来划分更细粒度的内存供调用者使用。也就是说系统先用页分配器分配以页为最小单位的连续物理地址,然后 kmalloc() 再在这上面根据调用者的需要进行切分。

关于以上论述,我们可以查看 kmalloc() 的实现,kmalloc()函数的实现是在 __do_kmalloc() 中,可以看到在 __do_kmalloc()代码里最终调用了 __cache_alloc() 来分配一个 slab,其实

kmem_cache_alloc() 等函数的实现也是调用了这个函数来分配新的 slab。我们按照 __cache_alloc()函数的调用路径一直跟踪下去会发现在 cache_grow() 函数中使用了 kmem_getpages()函数来分配一个物理页面,kmem_getpages() 函数中调用的alloc_pages_node() 最终是使用 __alloc_pages() 来返回一个struct page 结构,而这个结构正是系统用来描述物理页面的。这样也就证实了上面所说的,slab 是在物理页面基础上实现的。kmalloc() 分配的是物理地址。

__get_free_page() 是页面分配器提供给调用者的最底层的内存分配函数。它分配连续的物理内存。__get_free_page() 函数本身是基于 buddy 实现的。在使用 buddy 实现的物理内存管理中最小分配粒度是以页为单位的。关于以上论述,我们可以查看__get_free_page()的实现,可以看到__get_free_page()函数只是一个非常简单的封状,它的整个函数实现就是无条件的调用 __alloc_pages() 函数来分配物理内存,上面记录 kmalloc()实现时也提到过是在调用 __alloc_pages() 函数来分配物理页面的前提下进行的 slab 管理。那么这个函数是如何分配到物理页面又是在什么区域中进行分配的?回答这个问题只能看下相关的实现。可以看到在 __alloc_pages() 函数中,多次尝试调用get_page_from_freelist() 函数从 zonelist 中取得相关 zone,并从其中返回一个可用的 struct page 页面(这里的有些调用分支是因为标志不同)。至此,可以知道一个物理页面的分配是从 zonelist(一个 zone 的结构数组)中的 zone 返回的。那么 zonelist/zone 是如何与物理页面关联,又是如何初始化的呢?继续来看 free_area_init_nodes() 函数,此函数在系统初始化时由 zone_sizes_init() 函数间接调用的,zone_sizes_init()函数填充了三个区域:ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM。并把他们作为参数调用 free_area_init_nodes(),在这个函数中会分配一个 pglist_data 结构,此结构中包含了 zonelist/zone结构和一个 struct page 的物理页结构,在函数最后用此结构作为参数调用了 free_area_init_node() 函数,在这个函数中首先使用 calculate_node_totalpages() 函数标记 pglist_data 相关区域,然后调用 alloc_node_mem_map() 函数初始化 pglist_data结构中的 struct page 物理页。最后使用 free_area_init_core()函数关联 pglist_data 与 zonelist。现在通以上分析已经明确了__get_free_page() 函数分配物理内存的流程。但这里又引出了几个新问题,那就是此函数分配的物理页面是如何映射的?映射到了什么位置?到这里不得不去看下与 VMM 相关的引导代码。

在看 VMM 相关的引导代码前,先来看一下 virt_to_phys() 与phys_to_virt 这两个函数。顾名思义,即是虚拟地址到物理地址和物理地址到虚拟地址的转换。函数实现十分简单,前者调用了__pa( address ) 转换虚拟地址到物理地址,后者调用 __va(a

来源:https://www.tulaoshi.com/n/20160129/1502013.html

延伸阅读
标签: 电脑入门
问题:12G内存。如果是,Win8下面如何操作? 回答:先纠正一个误区,虚拟内存是不能禁用的。虚拟内存,应该指的是页面文件(paging file,pagefile.sys),是操作系统将部分虚拟内存页面换到磁盘上存放的数据。文章较长,可以直接跳到最后一段看结论。 我们先看看物理内存中有什么数据吧,我也是12G内存,物理内存中不仅存放了各个进程的数据(Pr...
C语言的位字段是个比较有意思的特性。它的目的是在一个机器字中保存多个对象(每个对象占据若干bit),从而节省内存资源,同时又避免复杂的位运算。在此不再讨论位字段的具体语法,下面将研究位字段的存储特性。 先说含有多个字段(field)的字(word)所占空间的规律——含有多个字段的字的大小是所有字段的类型中的最长的那个的倍数。但要...
一、为什么用动态内存分配 但我们未学习链表的时候,假如要存储数量比较多的同类型或同结构的数据的时候,总是使用一个数组。比如说我们要存储一个班级学生的某科分数,总是定义一个float型(存在0.5分)数组: float score[30]; !-- frame contents -- !-- /frame contents -- 但是,在使用数组的时候,总有一...
一.概述2 二.例子程序简要说明2 三.server端2 四.client端3 五.Valgrind的使用3 六.参考文档4 七.备注4 一.概述 在gSOAP的server和client端连接中,内存的处理有些是gSOAP自己处理的,有些需要我们来考虑。本文档主要就其中目前可能碰到的内存问题,做一个简要的介绍及说明。另外,简要介绍...
标签: Web开发
看个例子: 1  代码如下: function a(){      alert("我是脚本之家");  }  2   代码如下: var a = function(){      alert("我是脚本之家");  }         1和2的方法是等价的...

经验教程

276

收藏

28
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部