第三阶段建立的是 buddy
mm_init->mem_init返回 - 无结束点
buddy 管理的内存 是 memblock 决定的
属于 memblock.memory 中 但不包括 memblock.reserved 的部分
memblock 可以通过 memblock_alloc或memblock_reserve 来 预留内存
buddy 的使用方法
alloc_pages/alloc_page
get_zeroed_page
__get_free_pages/__get_free_page
get_dma_pages
__get_free_pages
struct page *page = alloc_pages
alloc_pages_node
__alloc_pages_node
__alloc_pages
__alloc_pages_nodemask
struct page * page = get_page_from_freelist
return (unsigned long) page_address(page);
__alloc_pages_nodemask 的 具体细节
__alloc_pages_nodemask
prepare_alloc_context
get_page_from_freelist
__alloc_pages_slowpath
具体 查看 https://zhuanlan.zhihu.com/p/258921453
强烈推荐
prepare_alloc_context
1. struct alloc_context *ac
ac->migratetype = gfp_migratetype(gfp_mask);
2. gfp_t *alloc_mask
*alloc_mask |= __GFP_HARDWALL;
3. unsigned int *alloc_flags
*alloc_flags = current_alloc_flags(gfp_mask, *alloc_flags);
get_page_from_freelist
for_next_zone_zonelist_nodemask(zone, z, ac->highest_zoneidx, ac->nodemask) {
mark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK);
if (!zone_watermark_fast(zone, order, mark, ac->highest_zoneidx, alloc_flags, gfp_mask)) {
if (alloc_flags & ALLOC_NO_WATERMARKS) goto try_this_zone;
}
try_this_zone:
page = rmqueue(ac->preferred_zoneref->zone, zone, order, gfp_mask, alloc_flags, ac->migratetype);
if (likely(order == 0)) rmqueue_pcplist(preferred_zone, zone, gfp_flags, migratetype, alloc_flags);
else __rmqueue(zone, order, migratetype, alloc_flags);
__rmqueue_smallest(zone, order, migratetype);
area = &(zone->free_area[current_order]);
page = get_page_from_free_area(area, migratetype);
del_page_from_free_list(page, zone, current_order);
}
__alloc_pages_slowpath
调用内存短缺的各种机制
... relaim
... compact
... oom killer
... kswapd
get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
free_pages/free_page
__free_pages/__free_page
free_pages(unsigned long addr, unsigned int order)
__free_pages(virt_to_page((void *)addr), order);
free_the_page(page, order)
__free_pages_ok
free_one_page
__free_one_page
add_to_free_list(page, zone, order, migratetype);
其他
buddy系统 只会维护空闲的块,已经分配出去的块不属于buddy系统
对某一些块 调用 free_pages 后, 才会将其 放入 buddy 系统中
---
拆解&合并
buddy的本质就是按照 2^n 拆解&合并
1. 物理内存碎片问题
buddy 合并
时机: free_pages
方法:
线程:无
规整 compact
时机: alloc
方法:
线程: 1个线程 kcompactd0
2. 物理内存不足问题
回收 reclaim
时机: alloc内存紧缺时/周期/系统睡眠
方法:
线程: 2个线程 kswapd0 oom_reaper
3. 无法申请到连续的物理页
CMA contiguous memory allocator
时机: alloc连续内存时
方法:
预留一段的内存给驱动使用,但当驱动不用的时候,CMA区域可以分配给用户进程用作匿名内存或者页缓存。
而当驱动需要使用时,就将进程占用的内存通过回收或者迁移的方式将之前占用的预留内存腾出来,供驱动使用。
线程: 无
---
5. 如果 __GFP_DMA 被置位, 则 只能从 ZONE_DMA 内存管理区获取 page
6. 如果 __GFP_HIGH 没被置位, 则 依次从 ZONE_NORMAL ZONE_DMA 内存管理区获取 page
7. 如果 __GFP_HIGH 被置位, 则 依次从 ZONE_HIGHMEM ZONE_NORMAL ZONE_DMA 内存管理区获取 page
---
页框无限制,可存储任意数据
x86硬件对页框有限制 导致新增ZONE(ZONE对页框分类)
原来没有ZONE,或者只有一个ZONE : ZONE_NORMAL 16MB - 896MB
1.DMA只能对RAM前16MB寻址 : 新增了 ZONE_DMA 0MB - 16MB
2.32bit不能寻址所有的物理内存 : 新增了 ZONE_HIGHMEM 896M -
arm32呢???
页框无限制,可存储任意数据
arm32硬件对页框有限制 导致新增ZONE(ZONE对页框分类)
原来没有ZONE,或者只有一个ZONE : ZONE_NORMAL 0MB - 760MB
1.32bit不能寻址所有的物理内存 : 新增了 ZONE_HIGHMEM 760MB -
---
现状
没有配置CONFIG_ZONE_DMA CONFIG_ZONE_DMA32 CONFIG_HIGHMEM
只有两个 ZONE : ZONE_NORMAL ZONE_MOVABLE
---
对于arm32来讲,什么时候需要配置 CONFIG_HIGHMEM?
200MB 是不需要配置 CONFIG_HIGHMEM的
1GB 是需要配置的,因为内核空间只有1G,memblock预留之后小于1G,不能完全映射
---
6410 是 有 DMA 的
源和目标 在 系统总线/外围总线 中(4种情况) 皆可用
采用的是 ARM的 IP PL080
4个DMA ,每个DMA 8个通道
对内存没有限制