内核版本:linux-2.6.11


  • 伙伴系统

伙伴系统是linux用于满足对不同大小块物理内存分配和释放请求的解决方案。

  • 内存管理区

linux将物理内存分成三个内存管理区,分别为ZONE_DMA ZONE_NORMAL ZONE_HIGHMEM,并使用三个管理区描述符管理这三个ZONE。

管理区描述符里,有一个元素数为11的free_area数组,分别对应1、2、4、8、16.....不同块的大小,其中的每个元素的类型都是一个名为free_area的结构体,代码位置mm/mmzone.h

struct free_area {
struct list_head free_list;
unsigned long nr_free;
};

例如,该数组第三个元素的free_list保存了2的4次方即16个页框大小的空闲块链表,nr_free保存了空闲块的数量。

  • 块内存分配函数

代码位置 mm/page_alloc.c

__rmqueue,传入参数为order和管理区zone的描述符指针。

static struct page *__rmqueue(struct zone *zone, usigned int order);

该函数会遍历2的order次方个页框大小的块空闲链表,若该链表空,则将order+1继续遍历,找到非空的空闲块链表后,取得它的第一个页框描述符。

page = list_entry(area->free_list.next, struct page, lru);

list_entry是一个宏,功能是取得一个成员变量的父结构体的指针,这里的意思是获得第一个参数area->free_list.next所在的page结构体的指针。

接着从链表中删除它的这一个页框描述符,并减少管理区描述符中的free_pages的值。

从上述过程可以知道,在获取order对应大小的空闲块时,如果没有正好大小的空闲块,那么将会从更大的空闲块中分离出order对应大小的空闲块,分离后剩下的部分要按照伙伴系统的规则正确的记录到管理区描述符的free_area数组中,expand函数在做这件事的同时,将我们需要的空闲块的第一个页框描述符的private字段设置成order(因为这个private仍然是空闲块未分割时的order值)。

return expand(zone, page, order, current_order, area);

至此,已经找到了需要的空闲块,返回其中的第一个页框描述符指针。

  • 块内存释放函数

代码位置 mm/page_alloc.c

__free_pages_bulk,传入参数依次为要释放块的第一个页框描述符的指针,管理区的zone_mem_map字段(即管理区中的第一个页框描述符指针),管理区描述符,释放块的order值

static inline void __free_pages_bulk (struct page *page, struct page *base,
struct zone *zone, unsigned int order)

除去一些报错的代码后,主要过程就是寻找这个释放块的伙伴,并将二者合并。

函数实现部分,寻找伙伴这部分的代码理解起来比较晦涩,但十分聪明

buddy_idx = (page_idx ^ (1 << order));
buddy = base + buddy_idx;

page_idx是释放块在zone_mem_map中的下标,为了寻找它的伙伴块在zone_mem_map中的下标,将page_idx与块大小进行异或操作,该步骤可以将page_idx的第order位取反,即可以得到比page_idx高一个块大小的下标或者比page_idx低一个块大小的下标,这个下标值就是释放块的伙伴块在zone_mem_map中的下标。接着调用函数page_is_buddy来检查该伙伴块是否可以合并,若不行,退出循环,若行,将order+1并继续循环寻找是否有更大的伙伴块可以合并。

coalesced = base + page_idx;
set_page_order(coalesced, order);
list_add(&coalesced->lru, &zone->free_area[order].free_list);
zone->free_area[order].nr_free++;

循环结束后,page_idx记录了合并块的第一个页框描述符在zone_mem_map中的下标,加上base即zone_mem_map本身的地址后,得到合并块的第一个页框描述符的指针coalesced(这单词也够隐晦),该合并块成为最终的释放块,更新第一个页框描述符的private字段,并将其插入到适当链表,最后再增加该链表空闲块数量。

至此,块内存释放结束。

Linux内核笔记——内存管理之块内存分配的更多相关文章

  1. Linux内核笔记——进程管理之执行体

    内核版本:linux-2.6.11 在Linux中,有多种执行体(指令流.执行单位),它们是CPU调度和分配资源的基本单位,它们是内核态可见的,即内核态下,每一种执行体都有对应的唯一数据结构task_ ...

  2. Linux内核笔记--内存管理之用户态进程内存分配

    内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...

  3. Linux内核笔记——内存管理之slab分配器

    内核版本:linux-2.6.11 内存区和内存对象 伙伴系统是linux用于满足对不同大小块内存分配和释放请求的解决方案,它为slab分配器提供页框分配请求的实现. 如果我们需要请求具有连续物理地址 ...

  4. 【转载】linux内核笔记之高端内存映射

    原文:linux内核笔记之高端内存映射 在32位的系统上,内核使用第3GB~第4GB的线性地址空间,共1GB大小.内核将其中的前896MB与物理内存的0~896MB进行直接映射,即线性映射,将剩余的1 ...

  5. Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制

    Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches   Slab内存管理机制 SLUB内存管理机制 http://w ...

  6. 内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现

    http://blog.csdn.net/pi9nc/article/details/23334659 注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料 ...

  7. 【转载】linux内核笔记之进程地址空间

    原文:linux内核笔记之进程地址空间 进程的地址空间由允许进程使用的全部线性地址组成,在32位系统中为0~3GB,每个进程看到的线性地址集合是不同的. 内核通过线性区的资源(数据结构)来表示线性地址 ...

  8. 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配

    垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...

  9. Win3内存管理之私有内存跟共享内存的申请与释放

    Win3内存管理之私有内存跟共享内存的申请与释放 一丶内存简介私有内存申请 通过上一篇文章.我们理解了虚拟内存与物理内存的区别. 那么我们有API事专门申请虚拟内存与物理内存的. 有私有内存跟共享内存 ...

随机推荐

  1. java防止表单重复提交

    用session防止表单重复提交 思路:在服务器端生成一个唯一的随机标识串Token,同时在当前用户的Session域中保存这个Token.然后将Token发送到客户端的Form表单中,在Form表单 ...

  2. User space 与 Kernel space

    学习 Linux 时,经常可以看到两个词:User space(用户空间)和 Kernel space(内核空间). 简单说,Kernel space 是 Linux 内核的运行空间,User spa ...

  3. 渐进式框架、自底向上增量开发的vue

    官网对vue.js的介绍是这样的: 一套构建用户界面的 渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计. 那么到底什么是渐进式框架.自底向上增量开发又是什么呢? 其实我觉得这 ...

  4. Distinct Subsequences

    https://leetcode.com/problems/distinct-subsequences/ Given a string S and a string T, count the numb ...

  5. Lr中关于字符串的截取

    Action() { char separators[] = "\"processId\":\"";//截取条件 char * token; char ...

  6. WinForm各种API---时时更新

    好文要顶 关注我 收藏该文 徐淳 关注 - 1 粉丝 - 3       0 0     本文原文地址:http://www.cnblogs.com/hqxc/p/6160685.html 徐淳 [D ...

  7. nginx配置反向代理解决前后端分离跨域问题

    摘自<AngularJS深度剖析与最佳实践>P132 nginx配置文件如下: server { listen ; server_name your.domain.name; locati ...

  8. MySQL 排名统计

    select actor_id,@curr_cnt:=cnt as cnt , ,@rank) as rank, @prev_cnt:=@curr_cnt as dummy from( select ...

  9. iOS 编译时的警告导致无法通过编译

    今天编译react native的代码,发现了2个警告,但是系统却当做错误,不能编译成功,查看了一下编译选项,看到了如下配置: 注意到这个-Werror 了吗? 就是这个标志导致系统把所有的 警告都当 ...

  10. iOS CoreData 中 objectID 的不变性

    关于 CoreData的 objectID 官方文档有这样的表述:新建的Object还没保存到持久化存储上,那么它的objectID是临时id,而保存之后,就是持久化的id,不会再变化了. 那么,我想 ...