如题目所示,为什么要称作“内核内存管理”,因为内核所需要的内存和用户态所需要的内存,这两者在管理上是不一样的。

这篇文章描述内核的内存管理,用户态的内存管理在以后的文章中讲述。

首先简单的说明一下下面的描述所需要的基础知识:

1,以下描述适用于32位系统

2,32位系统的线性地址(或称为逻辑地址,下面统称为线性地址)0-4G,其中的3G-4G的地址空间由内核使用。宏PAGE_OFFSET 为0xC0000000(3G),也是内核空间和用户空间的分界。但是linux内核并没有把整个1G空间用于线性映射,而只能映射最多896M物理内存,预留了最高端的128M虚拟地址空间给IO设备和其他用途。所以,当系统物理内存较大时,超过896M的内存区域,内核就无法直接通过线性映射直接访问了。这部分内存被称作high memory。

3,high memory和low memory一样,都是参与内核的物理内存分配,都可以被映射到内核地址空间,也都可以被映射到用户地址空间。

4,物理内存<896M时,没有high memory,因为所有的内存都被kernel直接映射了。

5,64位系统下不会有high memory,因为64位虚拟地址空间非常大(分给kernel的也很大),完全能够直接映射全部物理内存。

6,内存的管理是页框为单位的,典型的X86下,不开启PAE时,页框的大小为4K

7,linux中内存的管理是分区(Zone)的,在X86体系结构中,分为ZONE_DMA(低于16M的页框),ZONE_NORMAL(16-896M页框),ZONE_HIGHMEM(大于等于896M页框)。

下面附录一张PAGE_OFFSET后的线性地址区间表,以供参考。

下面步入正题:

一,大尺度内存管理--伙伴系统算法

我们这篇文章描述的内核的内存策略,内核的首要出发点就是“性能”,因此内核申请内存时,最好是使用物理上连续的页框,原因有二:

1,在某些情况下,连续的页框确实是必要的,典型的例子是DMA,因为DMA忽略分页策略。

2,如果频繁的修改页表会导致频繁的刷新TLB,而连续页框分配可以减轻这点。

算法描述

把所有的空闲页框分为11个组,每组中的节点都以双向循环链表的形式链接起来,这11个组中的每一个节点的页框数分别为:1,2,4,8,16,32,64,128,256,512,1024。每个节点的页框都是连续的。

需要需要请求256个页框的节点(即1MB),算法先在256个页框的链表中检查是否有一个空闲的块,如果没有的话,算法会查找一个更大的节点,如果在512个页框的链表中找到了一个这样的节点,那么就把这个512个页框的节点分成两半,一半满足需求,另一半插入到256个页框的链表中。如果找到1024个页框的链表中也没满足需求,那么返回失败。

算法的逆过程就是释放的过程,算法会试图将大小为b的一对空闲节点(伙伴)合并成一个大小为2b的节点,这也是“伙伴”算法命名的由来。

算法使用的数据结构:

每个ZONE的结构体中,包含了一个struct free_area[] free_area的一个数组,这个数组有11个元素,第K个元素标识大小为2K个页框的链表,free_area中有个free_list字段是双向循环链表的头,free_area中有个nr_free字段代表链表中节点的个数。指向链表中相邻元素的指针放在页描述符的lru字段中。

每CPU页框高速缓存

内核经常请求和释放单个页框,为了提升系统性能,每个ZONE定义了一个“每CPU”页框高速缓存。

即struct per_cpu_pageset[] pageset数组,数组的大小为CPU的个数。数组中的每个元素由两个per_cpu_pages组成,一个留给热高速缓存,一个留给冷高速缓存。

struct per_cpu_pages { int count; int low; int high; int batch; struct list_head list}

内核通过high和low两个标识来管理缓存的大小,当页框的个数小于low,内核通过伙伴系统分配batch个页框来补充,释放的过程类似。

伙伴系统的算法其实还很复杂,例如当空闲页框较少时需要按一定的规则回收页框等,调用伙伴系统的路径是否在中断处理程序中也会有不同的对待,这些细节就不一一列举。

二,SLAB分配器

伙伴系统算法采用页框作为基本的内在区,这适合于大块的内存请求,那我们怎么处理对小内存区的请求呢,比如说几十或几百个字节?这就是我们下面要说的算法。

slab分配算法基本就包含在上图中了,首先声明几个概念:

对象:就是上面所说到的小的内存区,例如进程描述符,它所占用的内存区可以称为对象。

slab:可以理解为通过伙伴算法所申请的一个或几个连续的页框。它可以容纳N个对象。

高速缓存:每个高速缓存包含了相同类型的对象,高速缓存相当于一个对象的容器。高速缓存直接容纳的是slab,slab又容纳了对象。

普通或专用高速缓存:专用的高速缓存可以理解为专门存储一类对象,例如进程描述符,的高速缓存。而对于普通高速缓存,例如,某个高速缓存里面的对象都是100字节大小,那么这个普通高速缓存就可以存储所以小于100字节大小的对象。在系统初始化时,就创建了26(分为13对)个普通高速缓存,它们的大小呈现几何分布,分别为32,64,128,256... 131072。对于每一对,一个适用于ISA DMA分配,另一个用于常规分配。

1,算法简介

如上图所示,每一类高速缓存结构体中有三个字段,每个字段就是一个双向链表的头,分别是全满的slab,部分满的slab,空的slab。分别对应图中的三个圆角矩形。每一个双向链表把slab串起来,因为slab可以动态的增加或减少。

2,给高速缓存分配和释放slab

如果高速缓存为空,就调用伙伴系统分配一个slab,然后将构造方法(如果定义了的话)应用到新的slab所包含的所有的对象上。

每个高速缓存结构体都有两个字段void * ctor,dtor;分别表示这类对象的构造和析构方法。

将这个新的slab放到对应的双向链表中,并更新相关计数器。

释放的过程类似,使用析构方法释放所有的对象,并释放页框给伙伴系统。

细节(不在算法范围之内):给定一个页框,内核必须确定它是否被 slab分配器使用,并得到相应高速缓存和slab描述符的地址,这是通过页描述符的lru字段的next和pre子字段来实现,因为它分别存储了调整缓存描述符和slab描述符。反之,通过slab分配器也可以获取它占用的页框,这是通过高速缓存描述符的gforder字段(slab大小)和slab描述符的s_mem字段来实现。

3,本地高速缓存

为了减少多个CPU竞争slab分配器,每个高速缓存描述符都有一个array字段,它是一个数组,数组的大小是CPU的个数。它非常类似于上面所说的“每CPU页框高速缓存”。

linux内核--内核内存管理的更多相关文章

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

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

  2. 24小时学通Linux内核之内存管理方式

    昨天分析的进程的代码让自己还在头昏目眩,脑子中这几天都是关于Linux内核的,对于自己出现的一些问题我会继续改正,希望和大家好好分享,共同进步.今天将会讲诉Linux如何追踪和管理用户空间进程的可用内 ...

  3. Linux内核之内存管理

    Linux内核之内存管理 Linux利用的是分段+分页单元把逻辑地址转换为物理地址; RAM的某些部分永久地分配给内核, 并用来存放内核代码以及静态内核数据结构; RAM的其余部分称动态内存(dyna ...

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

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

  5. Linux内核之内存管理完全剖析

    linux虚拟内存管理功能 ? 大地址空间:? 进程保护:? 内存映射:? 公平的物理内存分配:? 共享虚拟内存.实现结构剖析   (1)内存映射模块(mmap):负责把磁盘文件的逻辑地址映射到虚拟地 ...

  6. 深入理解Linux内核-内存管理

    内核如果给自己分配动态内存 动态内存:RAM的某些部分被永久打分配给内核,用来存放内核代码以及静态内核数据结构:剩余的部分被称为动态内存 连续物理内存区管理: 页框管理:1.页大小的选择,通常情况下主 ...

  7. Linux 内核开发 - 内存管理

    1.1什么是内存管理 内存管理是对计算机内存进行分配和使用的技术.内存管理主要存在于多任务的操作系统中,因为内存资源极其有限.须要在不同的任务之间共享内存,内存管理的存在就是要高效.高速的非配内存,并 ...

  8. Linux内核之 内存管理

    前面几篇介绍了进程的一些知识,从这篇开始介绍内存.文件.IO等知识,发现更不好写哈哈.但还是有必要记录下自己的所学所思.供后续翻阅,同时写作也是一个巩固的过程. 这些知识以前有文档涉及过,但是角度不同 ...

  9. IA-32e架构下的内核初始化内存管理

    初级内存管理单元 关于内存的分页 以往的物理页是按照4KB进行分配和管理的, 而在Linux之后流行的就是2MB大小的物理页的分配和管理, 整个物理内存管理单元也是2MB物理页管理的 先获取基本的物理 ...

  10. PHP内核研究(内存管理1)

    PHP内存管理 PHP在5.3之前采用的是引用计数法 PHP在5.3之后采用了新的垃圾回收机制 操作系统在申请内存空间的时候回引发系统调用 在操作系统申请内存空间的时候,会将CPU从用户态切换到内核态 ...

随机推荐

  1. C# Linq To DataTable 分组统计 DEMO

    DataTable dt = SQLLayer.Get工作量统计(beginDate, endDate);             var querySum = from t in dt.AsEnum ...

  2. C#XML创建与节点对象引用

    我们在创建xml过程中会遇到不同的级别有相同节点的情况.如下面的xml: <?xml version="1.0" encoding="GBK"> & ...

  3. std::copy的使用

    看到有人在用std::copy这个东西,很简洁和爽啊,,所以找些帖子学习学习 http://blog.sina.com.cn/s/blog_8655aeca0100t6qe.html https:// ...

  4. Asp.net MVC2中你必须知道的扩展点(一):Controller Factory

    Asp.net mvc2中提供很多可以扩展的地方,利用这些扩展之后,asp.net mvc使用起来更加灵活.Simone Chiaretta曾写过一篇文章:13 ASP.NET MVC extensi ...

  5. Pentaho Data Integration (三) Pan

    官网连接: http://wiki.pentaho.com/display/EAI/Pan+User+Documentation Pan Pan 是一个可以执行使用Spoon编辑的transforma ...

  6. WiFi无线模块学习1——HLK-M30使用

    产品概述 概述: 通过该模块,传统的串口设备在不需要更改任何配置的情况下,即可通过Internet 网络传输自己的数据.为用户的串口设备提供完整快读的解决方案. 技术参数 可查询技术规格表 主要应用领 ...

  7. 单片机系统与标准PC键盘的接口模块设计

    转自单片机系统与标准PC键盘的接口模块设计 概述     在单片机系统中,当输入按键较多时,在硬件设计和软件编程之间总存在着矛盾.对于不同的单片机系统需要进行专用的键盘硬件设计和编程调试,通用性差,使 ...

  8. QLGame 2d Engine SpriteBatch类创建

    GitHub地址:https://github.com/wsgzxl/QLGame2dEngine 今天说五个问题: 1.前面说到的 颜色不对的问题,是因为FreeImage读取出来的数据格式与Ope ...

  9. 同一個Loader對象傳入不同參數時,从数据库中查询的結果每次都一樣

    發現問題: LoaderManager().initLoader()方法調用時會根據第一個參數ID去判斷是否已經存在一個Loader加載器,如果存在則複 用,不存在則建一個新的加載器.由於我第一次已經 ...

  10. Perl,Python,Ruby,Javascript 四种脚本语言比较

    Perl 为了选择一个合适的脚本语言学习,今天查了不少有关Perl,Python,Ruby,Javascript的东西,可是发现各大阵营的人都在吹捧自己喜欢的语言,不过最没有争议的应该是Javascr ...