本文共 4135 字,大约阅读时间需要 13 分钟。
第三阶段建立的是 buddy
mm_init->mem_init返回 - 无结束点
buddy 管理的内存 是 memblock 决定的属于 memblock.memory 中 但不包括 memblock.reserved 的部分memblock 可以通过 memblock_alloc或memblock_reserve 来 预留内存
alloc_pages/alloc_page // 返回的是 struct pageget_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 //1.准备参数 get_page_from_freelist //2.根据prepare_alloc_context 得到的参数 , 快路径尝试分配内存 __alloc_pages_slowpath //3.如果快路径尝试分配内存失败,慢路径尝试分配内存 具体 查看 https://zhuanlan.zhihu.com/p/258921453 强烈推荐prepare_alloc_context // 设置 get_page_from_freelist 函数的三个参数 1. struct alloc_context *ac ac->migratetype = gfp_migratetype(gfp_mask); // 设置 需要的 迁移类型 , 与 zone->free_area[order].free_list[migratetype] 相关 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) { // 按照 ZONE_HIGHMEM ZONE_NORMAL ZONE_DMA 的优先级 遍历zone mark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK); // 获取当前水位线 if (!zone_watermark_fast(zone, order, mark, ac->highest_zoneidx, alloc_flags, gfp_mask)) { // 与 alloc_pages 设置的 水位线FLAG 比较 // 此时进入 if 函数体 表示, 当前水位线 <= alloc_pages 设置的水位线FLAG,表示不能再分配物理页面 if (alloc_flags & ALLOC_NO_WATERMARKS) goto try_this_zone; // 表示 alloc_pages 设置的 水位线FLAG 表示 忽略 水位线,则直接到 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); // 查询 per_cpu_pages (pcp) 维护的 链表 是否可以满足内存申请 else __rmqueue(zone, order, migratetype, alloc_flags); // 从伙伴系统申请,查询的链表为 // zone->free_area[order].free_list[migratetype] __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_pagefree_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个线程 kcompactd02. 物理内存不足问题 回收 reclaim 时机: alloc内存紧缺时/周期/系统睡眠 方法: 线程: 2个线程 kswapd0 oom_reaper3. 无法申请到连续的物理页 CMA contiguous memory allocator 时机: alloc连续内存时 方法: 预留一段的内存给驱动使用,但当驱动不用的时候,CMA区域可以分配给用户进程用作匿名内存或者页缓存。 而当驱动需要使用时,就将进程占用的内存通过回收或者迁移的方式将之前占用的预留内存腾出来,供驱动使用。 线程: 无
---5. 如果 __GFP_DMA 被置位, 则 只能从 ZONE_DMA 内存管理区获取 page6. 如果 __GFP_HIGH 没被置位, 则 依次从 ZONE_NORMAL ZONE_DMA 内存管理区获取 page7. 如果 __GFP_HIGH 被置位, 则 依次从 ZONE_HIGHMEM ZONE_NORMAL ZONE_DMA 内存管理区获取 page---页框无限制,可存储任意数据x86硬件对页框有限制 导致新增ZONE(ZONE对页框分类)原来没有ZONE,或者只有一个ZONE : ZONE_NORMAL 16MB - 896MB1.DMA只能对RAM前16MB寻址 : 新增了 ZONE_DMA 0MB - 16MB2.32bit不能寻址所有的物理内存 : 新增了 ZONE_HIGHMEM 896M - arm32呢???页框无限制,可存储任意数据arm32硬件对页框有限制 导致新增ZONE(ZONE对页框分类)原来没有ZONE,或者只有一个ZONE : ZONE_NORMAL 0MB - 760MB1.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 PL0804个DMA ,每个DMA 8个通道对内存没有限制
转载地址:http://yjigi.baihongyu.com/