Linux内核笔记——内存管理之块内存分配
内核版本: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内核笔记——内存管理之块内存分配的更多相关文章
- Linux内核笔记——进程管理之执行体
内核版本:linux-2.6.11 在Linux中,有多种执行体(指令流.执行单位),它们是CPU调度和分配资源的基本单位,它们是内核态可见的,即内核态下,每一种执行体都有对应的唯一数据结构task_ ...
- Linux内核笔记--内存管理之用户态进程内存分配
内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...
- Linux内核笔记——内存管理之slab分配器
内核版本:linux-2.6.11 内存区和内存对象 伙伴系统是linux用于满足对不同大小块内存分配和释放请求的解决方案,它为slab分配器提供页框分配请求的实现. 如果我们需要请求具有连续物理地址 ...
- 【转载】linux内核笔记之高端内存映射
原文:linux内核笔记之高端内存映射 在32位的系统上,内核使用第3GB~第4GB的线性地址空间,共1GB大小.内核将其中的前896MB与物理内存的0~896MB进行直接映射,即线性映射,将剩余的1 ...
- 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 ...
- 内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现
http://blog.csdn.net/pi9nc/article/details/23334659 注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料 ...
- 【转载】linux内核笔记之进程地址空间
原文:linux内核笔记之进程地址空间 进程的地址空间由允许进程使用的全部线性地址组成,在32位系统中为0~3GB,每个进程看到的线性地址集合是不同的. 内核通过线性区的资源(数据结构)来表示线性地址 ...
- 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配
垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...
- Win3内存管理之私有内存跟共享内存的申请与释放
Win3内存管理之私有内存跟共享内存的申请与释放 一丶内存简介私有内存申请 通过上一篇文章.我们理解了虚拟内存与物理内存的区别. 那么我们有API事专门申请虚拟内存与物理内存的. 有私有内存跟共享内存 ...
随机推荐
- C++ 操作XML文件 使用MSXML.DLL
使用MSXML.DLL读写XML; 文件顶部加入 #import "msxml3.dll"; using namespace MSXML2; //这两句作用是,在程序的文件夹下生成 ...
- 2. K线学习知识二
1. K线 - 阳线 定义:阳线是证券市场上指收盘价高于开盘价的K线,K线图中用红线标注表示涨势. A:小阳星 全日中股价波动很小,开盘价与收盘价极其接近,收盘价略高于开盘价. 小阳星的出现,表明行情 ...
- oracle 关于null值排序
在oracle中根据字段来desc排序的话null值可能会在数据的最前面.然而有时候我们查看数据的时候并不希望能够在前面看到这些null值的排序数据. 因此我查了一下: 1.排序的时候运用nvl(). ...
- CSS3学习基本记录
CSS3 边框 border-radius: 圆角 border-radius: 15px 50px 70px 100px; 左上 右上 右下 左下 box-shadow:阴影 box-shadow: ...
- Struts开发包结构
- 【JSTREE】 复选框默认选中【总结】
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...
- ElasticSearch详解与优化设计
简介 概念 安装部署 ES安装 数据索引 索引优化 内存优化 1简介 ElasticSearch(简称ES)是一个分布式.Restful的搜索及分析服务器,设计用于分布式计算:能够达到实时搜索,稳定, ...
- repo 修改邮箱地址
需要重新运行 repo init 被带上参数: --config-name xx@a.com
- php给客户端返回数据注意。
亲身测试: 返回的时候不要直接返回字符串,要用数组的方式返回数据客户端才能接收. 看代码. <?php require_once("../base.php"); functi ...
- SpringMVC文件上传和下载
上传与下载 1文件上传 1.1加入jar包 文件上传需要依赖的jar包 1.2配置部件解析器 解析二进制流数据. <?xml version="1.0" encoding=& ...