linux底层使用伙伴系统-buddy管理物理内存,buddy可以被证明是一种很有效的内存管理方式,但是它也拥有很多缺点,其中碎片避免的不完备性--仅仅寄托于释放时的合并操作而不考虑分配时的策略,这也许是它最大的不足,linux2.6内核的后期版本对这个问题进行了改进,大大避免了碎片的泛滥。在linux中,buddy是通过下列数据结构表示的(2.6的早期内核): 
struct free_area {
    struct list_head    free_list;
    unsigned long        *map;
};
系统中10个free_area组成一个数组,每一个free_area包含一个链表,每一个链表上链接有空闲内存页面块。后来引入了MIGRATE_TYPE,于是free_area结构体就成了:
struct free_area {
    struct list_head    free_list[MIGRATE_TYPES];
    unsigned long        nr_free;
};
每一个free_area包含多个链表,其中每一个链表中的内存页面按照其自身是否可以释放或者迁移被归为一类,于是凡是请求“不可迁移”页面的分配请求全部在free_list[MIGRATE_UNMOVABLE]这条链表上分配,和老版本一样,系统中有10个free_area代表大小为2的N次幂个不同页面的集合。这种归类可以最小化内存碎片。
     buddy系统本身就有效的防止了碎片,然而还不够。
buddy主要体现在:1.互为buddy的页面块不可能共存于一个free_area链表,它们总是倾向于合并;2.一个free_area的链表中的页面order相同,但是它们肯定彼此不互为buddy,这些页面用于该order大小需求的页面分配。但是buddy的碎片防止机制寄托于内存使用者会及时释放掉内存的情况,如果使用者长期不释放内存,或者说在使用者还没有释放内存的这一段时间期间,碎片将是存在的,并且可能还会导致很大的问题,比如在物理内存中间分配了一页面,然而仅因为分配的这一个页面不可移动,在它被释放之前,系统可用的最大的连续物理内存就只有不到一半物理内存总大小了。究其根源,这种问题的根源在于buddy系统仅仅释放页面时的合并操作防止了碎片的产生,不管页面从哪里被分配,只要它能有效被释放,碎片就是可以避免的,也就是说,buddy系统对于分配并没有更多的约束,仅仅满足在10个free_area中从小到大的顺序扫描即可。
     既然找到了buddy的问题,那么只要对分配动作采取一定的约束,碎片就可以进一步避免了。
最简单而又不引入过多复杂性的办法就是将页面按照“可移动”属性分类,将不可移动的页面分为一类,将可以移动的页面分为一类,它们各自占据一块足够大的连续物理空间,不可移动的页面分配需求则尽量在它自己的页面类中分配,可移动的页面也一样,这样一来,不可移动的页面的不可移动性仅仅影响它自身的类别而不会导致一个不可移动的页面两边都是可移动的页面。这就是MIGRATE_TYPE被引入的目的。MIGRATE_TYPE限制了内存页面的分配地点从而避免碎片,而不再仅仅寄希望于它们被释放时通过合并避免碎片。
     可以说MIGRATE_TYPE仅仅是一种防止碎片的策略,不应该因为它的存在而影响到内存分配的结果,也就是说,如果在一个MIGRATE_TYPE链表中没有内存可以分配了,那么也还是可以从别的链表中“暂时抢”一些的。另外,还有一个问题,内核载初始化的时候如何为“不可移动类”或者“可移动类”页面指定初始大小呢?也就是说,一开始,系统的free_area中的这些类别链表的页面各该是多少个呢?事实上,内核从来没有指定过初始大小,而是一开始将所有页面都归到“可移动”组当中,而别的组全部都是空的,等到真的有不可移动页面需求的时候再从可移动组中拨一批给不可移动组链表,想一下这也是合理的,毕竟只是一些“不可移动”的页面造成了内存的长期碎片化,如果没有这些长期使用的不可移动页面,碎片的问题是不大的。这个从__rmqueue_fallback函数中可以看出,系统的内存子系统拥有一个fallbacks序列,该序列展示了一个分配序列,也就是如果一个migratetype链表中如果分配不到内存的话,下一个应该在哪个migratetype链表中分配。从__rmqueue_fallback可以看出,如果从要求的migratetype空闲链表中分配不到内存的话,并不是在根据fallbacks序列在“下一个”链表中仅仅分配到自己本次所需的就完事了,而是一次性从fallbacks序列中指示的链表中转移足够多的页面到分配时要求的migratetype链表,毕竟该种类型的空闲链表已经没有页面了,确实需要补充了,并且如果补充的页面太少,那么就会给转移的源migratetype类型组造成碎片,只有一次性分配一大块内存,才不至于引入碎片。
static struct page *__rmqueue_fallback(struct zone *zone, int order,
                        int start_migratetype)
{
    struct free_area * area;
    int current_order;
    struct page *page;
    int migratetype, i;
    //尽量一次性拨出尽可能多的内存页面给“该”migratetype的free_area链表
    for (current_order = MAX_ORDER-1; current_order >= order; --current_order) {
        for (i = 0; i < MIGRATE_TYPES - 1; i++) {
            migratetype = fallbacks[start_migratetype][i];
            if (migratetype == MIGRATE_RESERVE)  //不允许占用保留内存
                continue;
            area = &(zone->free_area[current_order]);
            if (list_empty(&area->free_list[migratetype]))
                continue;
            page = list_entry(area->free_list[migratetype].next, struct page, lru);
            area->nr_free--;
            ...
            list_del(&page->lru);
            rmv_page_order(page);
            __mod_zone_page_state(zone, NR_FREE_PAGES, -(1UL << order));
            if (current_order == pageblock_order)
                set_pageblock_migratetype(page,    start_migratetype);
            //将除去本次自己要用的page[order]之外的其它页面全部补充进该area的migratetype空闲链表
            expand(zone, page, order, current_order, area, migratetype);
            return page;
        }
    }
    return __rmqueue_smallest(zone, order, MIGRATE_RESERVE);
}

另外,还有一种类似的机制用于避免碎片,那就是使用ZONE的概念,新构造出一个虚拟的ZONE--ZONE_MOVABLE,所谓的虚拟就是它并不和任何物理内存区间相关联,而是可以附着在任何的物理zone上,用户可以通过命令行参数指定用于“可移动”或者“不可移动”的内存的大小,从而也就规定了虚拟的ZONE_MOVABLE的大小。一般的最终比较高的物理内存区域用于可移动的虚拟zone(ZONE_MOVABLE)分配,这是因为低地址内存更多的用于dma或者isa或者内核数据结构(一一线性映射)等,而高内存则一般用于用户进程(可以交换到交换空间...)

本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1271151

linux内核对伙伴系统的改进--migrate_type相关推荐

  1. linux开源社区贡献代码,4岁小萝莉向Linux内核贡献代码修复「漏洞」而且代码已经合并到内核...

    最近国外社区 Reddit 上有个非常有趣的讨论 ,  在过去发布的Linux内核中有处代码改进是名4岁的小萝莉提交的. 这名小萝莉向内核提交代码以修复某处「漏洞」,这次代码修订还是在 2014 年发 ...

  2. 冒充linux内核,4岁小萝莉向Linux内核贡献代码修复「漏洞」而且已经合并到内核...

    最近国外社区 Reddit 上有个非常有趣的讨论 , 在过去发布的 Linux 内核中有处代码改进是名4岁的小萝莉提交的. 这名小萝莉向内核提交代码以修复某处「漏洞」,这次代码修订还是在 2014 年 ...

  3. 【Linux内核】Linux内核介绍

    Linux学习内核思路 学习过程: Linux内核引导及如何初始化 进程管理.内存管理 内核引导及过程: CPU通电后,首先执行引导程序,引导程序把内核加载到**内存,**然后执行内核,内核初始化完成 ...

  4. Linux 内核 4.20 圣诞发布!新增硬件支持,性能有所改进

    就在圣诞节前夕,Linus Torvalds于12月23日正式宣布发布Linux 内核4.20.在官方声明中,Linus Torvalds表示他不会考虑再延迟一周,因为所有人都要休假了. 我鼓励大家及 ...

  5. linux内核内存slab,伙伴系统,内存碎片,内存耗尽(OOM)杀手,内存资源控制器memcg,KASAN学习笔记

    目录 1 基础知识 1.1 页 1.2 页表 1.3 UMA(一致性访问) / NUMA(非一致性访问) 1.4 高端内存和低端内存 1.5 内存模型 2 物理内存的管理 2.1 物理内存的组织:节点 ...

  6. 奔跑吧Linux内核初识

    断更新博客有一段时间了.入职两年了一家创业公司,那是真心的累,当然了获得了技术上很大的提升.搞了两年的vr产品,唯一遗憾的是,平台是ST单片机,远离了系统级别的知识.回看刚出校园时的三年计划,和第一年 ...

  7. 关于Linux内核的一些问题

    1)      Linux中主要有哪几种内核锁?     Linux的内核锁主要是自旋锁和信号量. 自旋锁最多只能被一个可执行线程持有,如果一个执行线程试图请求一个已被争用(已经被持有)的自旋锁,那么 ...

  8. epub 深入linux内核架构_深入分析Linux内核源代码6-Linux 内存管理(2)

    每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你! ----零声学院 6.3 内存的分配和回收 在内存初始化完成以后,内存中就常驻有内核映像(内核代码和数据).以后,随着用 户程序的执行 ...

  9. linux内核分析(转自某位大哥网上的笔记)

    启动 当PC启动时,Intel系列的CPU首先进入的是实模式,并开始执行位于地址0xFFFF0处的代码,也就是ROM-BIOS起始位置的代码.BIOS先进行一系列的系统自检,然后初始化位于地址0的中断 ...

最新文章

  1. 面试:高频面试题:如何保证缓存与数据库的双写一致性?
  2. linux 编译sqlitecpp,编译安装sqlite3数据库
  3. 011_Raphael常用方法
  4. Web.xml 文件与server.xml 文件使用总结
  5. C++程序的执行过程
  6. 2017-2018-1 20155330 《信息安全系统设计基础》第11周学习总结
  7. Spring MVC Boot Cloud 技术教程汇总(长期更新)
  8. Java编程解密-Dubbo负载均衡与集群容错机制
  9. SpringMVC请求后台地址URL没有.*的几种实现方式
  10. 牛客编程巅峰赛S2第7场 - 钻石王者
  11. node创建ETH地址及导出私钥
  12. 手游服务器常用架构图
  13. Java8 Stream,过分丝滑!
  14. 千锋python培训机构可靠吗
  15. 团队协作常见问题分析与解决
  16. N1盒子安装 aria2(带AriaNg前端)
  17. 编译低版本的binutils-2.16.1错误:ld.texinfo:1592: @itemx must follow @item
  18. 你值得拥有!-阿里P8架构师荣耀典藏:Java多线程与Socket实战微服务框架笔记
  19. 94、DehazNeRF: Multiple Image Haze Removal and 3D Shape Reconstruction using Neural Radiance Fields
  20. 卸甲归田——回顾CSP2019

热门文章

  1. DCMTK:数据字典测试程序
  2. VTK:Points之ExtractEnclosedPoints
  3. Qt Creator连接QNX设备
  4. Qt Creator将应用程序部署到QNX Neutrino设备
  5. OpenGL Texture Wrap Modes纹理包裹模式的实例
  6. OpenGL索引呈现
  7. QT的QQmlPropertyMap类的使用
  8. QT的QBufferDataGenerator类的使用
  9. 安装驱动器于当前运行的windows驱动器不能相同_如何预防硬盘故障?5个迹象表明硬盘驱动器即将故障...
  10. Clickhouse Engine kafka 将kafka数据同步clickhouse