前情提要:

  1. 地址转换
  2. 物理页面的分配

终于到了物理内存的释放. 内存页面如生命一般. 有生有死.
接下来我们就要为物理页面抬棺收尸了.

1.要点: 如何为兄弟抬棺回收?

分配时跟谁分开的, 回收时要跟他一起才能被释放 双生小鬼

2.代码分析

  • 函数调用关系:
  • __free_pages_ok函数流程图

不是很清楚, 可私信要清楚的版本.如果我还存了的话

  • 代码
static void __free_pages_ok (struct page *page, unsigned int order)
{unsigned long index, page_idx, mask, flags;free_area_t *area;struct page *base;zone_t *zone;if (PageLRU(page)) /*检测该page是否在page lists中如果在, 就删除*/lru_cache_del(page);if (page->buffers) // 如果page被用作磁盘块缓存时BUG();if (page->mapping) //如果page有指向的inodeBUG();/*检测 ((page - mem_map) < max_mapnr) 是否超过page管理单元总数page 是否在有效的 [mem_map,mem_mep+max_mapnr]范围内*/if (!VALID_PAGE(page))BUG();if (PageSwapCache(page))BUG();if (PageLocked(page))BUG();if (PageLRU(page))BUG();if (PageActive(page))BUG();/*释放page标志位, 进而释放该order页*/page->flags &= ~((1<<PG_referenced) | (1<<PG_dirty));/*current : 当前运行的进程current在i386上定义为static inline struct task_struct * get_current(void){struct task_struct *current;__asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));return current;}#define current get_current()*/ if (current->flags & PF_FREE_PAGES)//若当前进程的标志位为每个进程物理页框释放goto local_freelist;
back_local_freelist:zone = page->zone; //指向该page属于的zonemask = (~0UL) << order; // mask = 页面指数order的掩码base = zone->zone_mem_map; // 该zone的所有4k页面的起始mem_map虚拟地址/**减运算page - base //(同类型结构体)表示从base到page 一共有多少个 sturct page 这样的结构体,即一共有多少个页,计算该page是第几个页, 即page在所有页中的页帧号       */page_idx = page - base; if (page_idx & ~mask) // 该page一定是(1<<order)字节对齐的BUG();//不是则报错index = page_idx >> (1 + order);// 使用buddy算法,求得该page对应的map管理位图值/** 加运算zone->free_area 所在地址加order个 free_area_t  结构体大小结构块之后的最终地址即free_area[order]*/area = zone->free_area + order; spin_lock_irqsave(&zone->lock, flags);//上锁zone->free_pages -= mask; // 将释放的空闲页数目, 加入到该zone的free_pages///*每次mask<<= 1 当mask = -512 此时while(0) 退出*/while (mask + (1 << (MAX_ORDER-1))) { //这里判断具体见示例程序struct page *buddy1, *buddy2;if (area >= zone->free_area + MAX_ORDER) //若area 越界,即free_area数组下标越界BUG();/*对 index进行异或运算, 返回0, 表示伙伴不在当前area内, 或者伙伴忙, 或者伙伴在其他area空闲着*/if (!__test_and_change_bit(index, area->map))/** the buddy page is still allocated.*/break;/*根据expend的分配规则寻找分配时跟哪个页框分开的,回收时就找它合并*/buddy1 = base + (page_idx ^ -mask); // 伙伴的page单元,通过^运算, 一下子找到伙伴的页帧号buddy2 = base + page_idx; //自己的page单元/*确保两个page单元都是合法的#define BAD_RANGE(zone,x) (((zone) != (x)->zone) ||  //非本page对应的zone(((x)-mem_map) < (zone)->zone_start_mapnr) ||  // 小于该zone管理的起始偏移(((x)-mem_map) >= (zone)->zone_start_mapnr+(zone)->size)) / 超过该zone->size 管理上限偏移*/if (BAD_RANGE(zone,buddy1)) BUG();if (BAD_RANGE(zone,buddy2))BUG();//list_delmemlist_del(&buddy1->list); // 伙伴 buddy1 从空闲链表删除mask <<= 1; // 去 order+1 执行上面同样的 buddy合并算法area++; // 下一个高位 areaindex >>= 1; // 计算位图管理位索引号page_idx &= mask; //更新page_idx,即更新为合并之后的page_idx}/*#define memlist_add_head list_add将经过Buddy合并后的页, 添加到相应area的free_list中*/memlist_add_head(&(base + page_idx)->list, &area->free_list);spin_unlock_irqrestore(&zone->lock, flags);//释放锁return;local_freelist:if (current->nr_local_pages)// 如果已经有local_pages, 将page释放到area->free_list中goto back_local_freelist; if (in_interrupt()) // 在中断中, 也需要将page释放到area->free_list中goto back_local_freelist;      //释放到 current->local_pages中list_add(&page->list, &current->local_pages);page->index = order; // 标记该page后面还有多少可用页面current->nr_local_pages++;// 当前进程持有的物理页帧递增
}
  • 提示
    函数中的while (mask + (1 << (MAX_ORDER-1)))可能会令人迷惑.我写了一个小demo.
#include<stdio.h>
#define MAX_ORDER 10
int main(){unsigned long mask= (~0UL) << 1 ;while( mask+(1<<(MAX_ORDER-1))) {mask<<=1;printf("unsigned mask = %lu\n",mask);printf("signed mask = %ld\n",mask);}return 0;
}

结果如下

自旋锁&信号量

  • 自旋锁
--自旋锁自旋锁不会引起调用者睡眠,且自旋锁保持期间是抢占失效的
--自旋锁API1.spin_lock(lock)只有获得锁才返回, (获得不到锁,将自旋直到自旋锁的持有者释放)2.spin_unlock(lock)释放自旋锁3.spin_trylock(lock)尽力获得自旋锁lock.if 立即能获得锁获得锁并返回真else立即返回假4.spin_lock_irqsave(lock, flags)#define spin_lock_irqsave(lock, flags)        do { local_irq_save(flags);       spin_lock(lock); } while (0)获得自旋锁的同时也把标志寄存器的值保存到flags中并失效本地中断5.spin_unlock_irqrestore(lock, flags)#define spin_unlock_irqrestore(lock, flags) do { spin_unlock(lock);  local_irq_restore(flags); } while (0)释放自旋锁的同时也恢复标志寄存器的值为变量flags保存的值, 与spin_lock_irqsave配对使用
  • 信号量
 --信号量会导致调用者睡眠,因此只在进程上下文使用,可被抢占适合于保持时间较长的情况

感想

现在,逻辑地址到物理地址的转换,物理内存分配与回收就算写完了.
希望我的经验可以帮到你.
页面转换不算难, 不过细节问题还是值得注意的.
比如说GDT, LDT放的位置,当然是专门的硬件了经典解决方案.
buddy系统的分析也是不少, 但是我还是要查好多资料.

虽然说我写的不算很详细, 但是应付学习一下操作系统课程的代码. 还算可以的. 下一篇会有一个简短的要点总结. 提分要素

参考

1、蒋静.操作系统原理·技术与编程.北京:机械工业出版社.2004
2、余华兵.Linux内核深度解析基于ARM64架构的Linux4.x内核.北京:人民邮电出版社.2019
3、河秦.王洪涛.Linux2.6内核标准教程.北京: 人民邮电出版社.2008
4、linux内核分析-内存管理
5、Linux_虚拟地址、线性地址和物理地址的转换
6、linux内核研究笔记4(do_wp_page参数
7、逆向映射的演进
8、页框的回收
9、The Buddy System Algorithm

Linux内存管理: 物理内存的释放(回收).为物理页面抬棺相关推荐

  1. Linux 内存管理 | 物理内存、内存碎片、伙伴系统、SLAB分配器

    文章目录 物理内存 物理内存分配 外部碎片 内部碎片 伙伴系统(buddy system) slab分配器 物理内存 在Linux中,内核将物理内存划分为三个区域. 在解释DMA内存区域之前解释一下什 ...

  2. Linux 内存管理 | 物理内存管理:物理内存、内存碎片、伙伴系统、slab分配器

    文章目录 物理内存 物理内存分配 内存碎片 外部碎片 内部碎片 伙伴系统(buddy system) slab分配器 本文举例为32位Linux 物理内存 在Linux中,内核将物理内存划分为三个区域 ...

  3. Linux内存管理--物理内存分配【转】

    转自:http://blog.csdn.net/myarrow/article/details/8682819 1. First Fit分配器 First Fit分配器是最基本的内存分配器,它使用bi ...

  4. Linux内存管理(三十九):页面回收简介和 kswapd详解(1)

    源码基于:Linux5.4 0. 前言 在 LRU简介 一文和 LRU 第二次机会法 一文中,提到当内存出现紧张的时候,会将 inactive list 尾部的 page 进行换出,从而将page 释 ...

  5. Linux 内存管理 | 地址映射:分段、分页、段页

    文章目录 分段 分页 多级页表 快表(TLB) 段页式 Linux Linux 内存管理 | 物理内存管理:内存碎片.伙伴系统.slab分配器 Linux 内存管理 | 虚拟内存管理:虚拟内存空间.虚 ...

  6. (六)Linux内存管理 - zoned page frame allocator - 1

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  7. linux内存管理的主要概念是虚拟内存,有关linux内存管理机制的相关内容,linux物理内存和虚拟内存,深入了解Linux内存运行 ......

    在linux中空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然. 这是Linux内存管理的一个优秀特性,区别于Windows的内存管理. 主要特点: 无论物理内存有多大,L ...

  8. linux内存管理(十一)-页回收总览

    随着linux系统不断分配内存,当系统内存压力越来越大时,就会对系统的每个压力大的zone进程内存回收,内存回收主要是针对匿名页和文件页进行的.对于匿名页,内存回收过程中会筛选出一些不经常使用的匿名页 ...

  9. linux内存管理笔记(三十九)----kswapd内存回收

    在linux操作系统中,当内存充足的时候,内核会尽量使用内存作为文件缓存(page cache),从而提高系统的性能.例如page cache缓冲硬盘中的内容,dcache.icache缓存文件系统的 ...

最新文章

  1. 【转载】中文输入法下onKeyPress不能触发的问题
  2. Linux-文件查找
  3. 面试题5,接口和抽象类的区别
  4. python 项目环境包的名称和版本导出和导入
  5. 网络爬虫中的Unicode码解决[实例]
  6. this关键字 和 private关键字
  7. 玩转spring boot——结合AngularJs和JDBC
  8. BeautifulSoup实现博文简介与过滤恶意标签(xxs攻击)
  9. Linux上安装RePlace
  10. 干货!软考高级网络规划设计师备考经验分享
  11. ns3学习之初识ns3
  12. 读《IPD华为研发之道》笔记
  13. 使用nodejs pkg创建exe文件后更改图标
  14. 整体看看Android的多媒体系统(多图)
  15. [原]几条简单命令查询硬件信息
  16. 函数的可重入和不可重入
  17. kubernetes-1.23.6版本部署
  18. RecyclerView 瀑布流错乱
  19. 利息计算的方式及实现
  20. 哈工大计算机学院2017届就业报告,2017年高校就业质量统计:哈尔滨工业大学

热门文章

  1. 拼多多2021笔试真题集
  2. 【Tomcat下载及使用说明】
  3. 推荐一个免费的论文查重网站
  4. 以互联网思维做好客户端软件
  5. 如何布署 PyTorch 深度学习模型
  6. Allegro如何快速删除孤立铜皮操作指导
  7. 希捷公布部分硬盘存在固件缺陷
  8. 16 OAuth2登录流程分析
  9. mybatis plus 分页(IPage)
  10. AI王者荣耀(python+minitouch+scrcpy)Transformer