关于ARM-Linux在内存管理初始化过程中的一点困惑
本帖最后由 paul719 于 2014-12-04 13:26 编辑刚开始研究ARM-linux内核,有个小问题希望大家讨论原因,帮忙解答...
在内存管理的初始化阶段的后期,Linux内核会使用buddy system替换初始阶段的bootmem分配器,这个过程在meminit()实现,在这个替换过程中有一个阶段叫做free_unused_memmap_node,调用过程如下:
meminit()
|--->free_unused_memmap_node(node);
|--->free_memmap(node, prev_bank_end, bank_start);
|--->free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
free_unused_memmap_node这个函数,看名字大概就是说释放掉未使用的页。我的理解,unused的意思大概也就是说bank与bank之间有些不可用的地址,
需要找到这些地址,然后把它从可分配的地址空间中刨除。在操作系统自动为申请内存操作分配页框时,就不会把这些未使用的内存地址分配出去。
举例,假如是图中黑色区域未接内存
这个刨除unused地址区域的函数到最后调用的是free_bootmem_node(),让我搞不懂的地方来了,这个函数是将bitmap中相应的页框置0,表示可分配的页。
明明这个地址对应的页框未使用,后面又将bitmap中对应的位设置为可分配,是什么原因呢?这些bitmap中设置为0的区域将来应该是要交给buddy system管理的
可供分配的内存啊?是我理解有问题么? 没有去看代码,按印象给你答。
1. 你理解的unused有误。这里所指的unused,是指没有被bootmem分配出去的内存。你想想,如果别人从bootmen分配了内存,一直在用,没有换给bootmem,再由buddy去管理时,也应该属于它的。如果在free_unused_memmap_node函数里还给buddy,那其它人就能从buddy申请到,这决对是不行的。
2. 一般来于,Linux所能用的物理内存是连续的,称为一致性内存,如果像你这种情况,物理内存都不连续了了,就是非一致性内存。此时,每一段内存都是一个node。free_unused_memmap_node会一个一个node的去处理node内的unused内存。 本帖最后由 paul719 于 2014-12-05 10:41 编辑
回复 2# Tinnal
谢谢版主解答,但是还是不理解。。。。版主可能还没真正理解我的疑惑~
详细阐述一下:
看最后的调用函数,确实是像你所说的,这里的unused是未被bootmem分配出去的内存。为了说清楚我的问题,我把bootmem到buddy system过渡阶段,尽可能说明白一些。
我们说对于bootmem的视角来看,就分为"已被分配出去的内存"和“未分配出去的内存”。
已被分配出去的内存(bitmap位:1)很简单,当然不可能交给buddy system的free_list(比如内核代码段区域),这个后面也会将这部分bit置1的区域交给reserve_list。
未被分配出去的内存(bitmap位:0)在我看来应该是两部分构成:1 可以分配给内核使用但尚未使用的 2 不可以使用的内存。
假如说未被分配出去的内存不存在第二种情况-不可以使用的内存,就清楚多了,去查bitmap位就好了,已分配的交给buddy system的reserve保留页列表,未分配的交给free空白页列表。
但是,这里出现了第二种情况,不可使用的内存,这里可能是版主和我存在理解不一样的地方,也是我迷惑的地方:
未被分配出去的内存就一定能交给buddy system的空白页链表,作为供内核申请的可用空间吗?我的理解是,不可以!不可以使用的内存就不能交给free空白页列表。
为什么会说有个不可使用的内存呢(也就是图中那个黑色区域)?版主在回复的第2点的说明可能认为这个区域根本不存在,因为内核要物理内存连续。我想说:
第一,一致性内存的概念应该是相对于线性地址空间而言的,物理地址不一致并不影响线性地址空间的一致性。
第二,这里的不可使用的内存也不是凭空捏造的,很多资料都有说到早期的处理器,内存bank之间是有hole的概念的,这里的洞也就是说有一块儿地址存在,但不可操作使用的空间,主要原因是受硬件制约,图中为了方便理解,可能画的夸张一点,实际上即使两个bank的物理地址空间紧挨着,在早期的处理器中,两个bank相邻的一块区域也是不可被操作的。
而且从代码中可以看出来:
free_memmap(prev_bank_end, bank_start);
注意看标红的参数,第一个参数是前一个bank的结束,第二个参数是当前bank的开始。用前一个bank的结束和后一个bank的开始标记的区域,难道不是不可用区域吗?因为bank本来就是描述可用物理内存的数据结构,不管是分配的内存和没有分配的内存,能用的都必然在bank范围之内,而这里的区域很明显在bank之外。
版主也说了,free_unused_memmap_node指定的区域,交给buddy system后,如果有人申请内存,系统就有可能把这块地址空间交给他使用。可是,再看看上面那个函数标红的区域,那一块区域在bank范围内吗?能用吗?如果是不可用,那为什么最后调用mark_bootmem(start, end, 0, 0)将这块区域设置成可分配区域?
附这部分源码:
static inline void
free_memmap(unsigned long start_pfn, unsigned long end_pfn)
{
struct page *start_pg, *end_pg;
unsigned long pg, pgend;
/*
* Convert start_pfn/end_pfn to a struct page pointer.
*/
start_pg = pfn_to_page(start_pfn - 1) + 1;
end_pg = pfn_to_page(end_pfn - 1) + 1;
/*
* Convert to physical addresses, and
* round start upwards and end downwards.
*/
pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
/*
* If there are free pages between these,
* free the section of the memmap array.
*/
if (pg < pgend)
free_bootmem(pg, pgend - pg);
}
void __init free_bootmem(unsigned long addr, unsigned long size)
{
unsigned long start, end;
kmemleak_free_part(__va(addr), size);
start = PFN_UP(addr);
end = PFN_DOWN(addr + size);
mark_bootmem(start, end, 0, 0); //对应区域的bitmap置0,表示可分配
}
楼主你是对的,free_unused_memmap_node函数释放掉内存节点中空洞空间的page数据结构。如果保留这些结构会占用大量的内存空间,同时页会给分配带来麻烦
页:
[1]