当前课程知识点:Linux 内核分析与应用 >  第4章 内存管理 >  4.4 物理内存分配与回收机制(下) >  Video

返回《Linux 内核分析与应用》慕课在线视频课程列表

Video在线视频

Video

下一节:Video

返回《Linux 内核分析与应用》慕课在线视频列表

Video课程教案、知识点、字幕

大家好 今天我们来讲一下内存分配

回收机制的第二讲

从这个图我们可以看出呢

从用户进程发出内存分配请求开始

到内核最终分配出物理内存

这中间内核要做大量的工作

那么上一讲我们概要的介绍了Vmalloc和Kmalloc

最终它们都要调用伙伴算法

通过get_free_page内核函数获得物理内存

那么目前呢有两种类型的计算机

分别以不同的方法来管理物理内存

它们分别是NUMA(non-uniform memory access)计算机

这是一种多处理器的计算机

是每个CPU拥有各自的本地内存

这样的划分使每个CPU呢

都能以较快的速度访问本地内存

而各个CPU之间通过总线连接起来

这样也可以访问其它CPU的本地内存

只不过呢速度比较慢而已

另外一种计算机叫UMA(uniform memory access)计算机

将可用内存以连续的方式组织起来 如图所示

为了兼容UMA模型呢 内核引入了内存节点

那么每个节点就关联了一个CPU

而各个节点又被划分为几个内存区

每个内存区中又包含了若干个页框

物理内存在逻辑上呢就

被划分为三级结构

分别使用三个数据结构pg_data_t zone和page来描述

节点 区和页框

UMA计算机中每个CPU的物理内存呢

我们称为一个内存节点

内核通过pg_data_t数据结构来描述

那么系统内的所有的节点就形成了一个双链表

UMA模型的物理内存只对应一个节点 也就是说

整个物理内存形成一个节点

因此上述的节点链表中也只有一个元素

关于内存管理区的话 我们说呢

各个节点划分为若干个区

也就是说物理内存的进一步细分

那么通过下面几个宏来标记物理内存的不同区

一个是ZONE_DMA

标识适合DMA的内存区

ZONE_NORMAL可以直接映射到内核空间的物理内存

ZONE_HIGHMEM叫做高端物理内存

那么32位和64位操作系统

对内存区管理上有什么差异呢

最大的区别是64位操作系统呢

不再有高端内存的概念

可以支持大于4GB的内存寻址

而且ZONE_NORMAL的空间将扩展到

64GB或者128GB

而且64位系统上的映射就变得更加的简单了

那么这三种数据结构之间它有什么关系呢

首先物理内存被划分为内存的节点

用pg_data_t来表示

那么每个节点实际上是关联了一个CPU

那么对于NUMA结构来说呢

因为有多个节点 因此各个节点就形成了一个链表

而每个节点又被划分成了几个内存管理区

在一个内存管理区中则是一个个的页框

页框是内存管理的基本单位

它可以存放任何类型的数据

下面我们对伙伴算法先进行一个概述

那么物理内存如何进行分配

Linux内核主要采用了伙伴算法

为什么叫伙伴算法呢 实际上呢就是

大小相同

物理地址连续的两个页框就被称为伙伴

那么Linux的伙伴算法把所有的空闲页面呢

分为多个块链表 如图所示

这个链表的个数呢默认值为11

每个链表中的一个块含有2的幂次个页面

也就是页块或者简称为块

比如说第一个链表里面是2的零次方个

页面 第二个是2的1次方个那么就分别是一个页面

两个页面 每个链表中的页块的大小呢它是不一样的

那么与伙伴算法有关的数据结构是什么呢

我们说每个物理页框它是要对应一个struct page实例

这是页框的描述数据结构

而每个内存区关联的是怎么样的一个数据结构呢

是struct zone的实例

那么该结构使用什么数据结构来描述空闲的页框呢

用free_area来描述

下面我们来对伙伴算法的分配原理给一个简要的解说

伙伴算法的分配原理是什么呢

就是说如果要分配阶为n的页框块的话

那么先从第n条页框链表中呢

查找是否存在这么大小的空闲页块

如果有的话那就分配

否则的话则在第n+1条链表中继续查找

直到找到为止

如果申请大小为8的页块的话

那么分配阶就是为3

但却在页块大小为32的链表中找到了空闲块

则先将这32个页面呢

对半等分

而前一半呢作为分配使用

另一半作为新元素插入下一

级大小为16的链表中

继续将前一半大小为16的页块等分

一半分配 另一半插入大小为8的链表中

那么页框的分配到底是怎么样来实现的呢

在这里我们主要介绍两个函数

第一个函数__rmqueue_smallest()是在指定的内存区上呢

从所请求的分配阶呢

对应的链表开始查找所需大小的空闲块

如果不成功则从高一阶的链表上继续查找

那么第二个函数expand()为分裂函数

如果所得到的内存块呢

大于所请求的内存块 则按照伙伴算法的分配原理呢

将大的页框块分裂成小的页框块

那么这是我们第一个函数的实现的源码

下面我们对这个函数的主要语句给予简单的介绍

实际上这个函数的实现是比较简单的

从当前指定的分配阶呢

到最高分配阶依次先进行遍历

在每次遍历分配阶的链表中呢

根据参数迁移类型呢

选择正确的迁移队列

根据以上的限定条件

当选定一个页块链表后呢

只要该链表不为空

就说明可以分配该阶对应的页块

一旦选定在当前遍历的分配阶链表上分配页框

那么就通过list_entry将该页块从链表中移除

以上这个过程通过rmv_page_order()完成

此外还要更新页块链表nr_free的值

那么下面是分裂函数expand()

这是这个函数的源代码

那么分裂函数的实现也是显而易见的

它完全遵照伙伴算法的分裂原理

这里有两个分配阶 一个呢是申请页框时指定的低阶(low)

一个是在上级函数中遍历时所选定的高阶(high)

该函数从高阶(high)分配阶开始

递减向低阶(low)遍历也就是说呢从

较大的页块开始呢依次分裂

那么什么是物理内存分配器呢

基于伙伴算法 每CPU高速缓存

和slab高速缓存形成了两种内存分配器

那么第一种呢是分区页框分配器(zoned page frame allocator)

处理对连续页框的内存分配请求

那么第二种呢是slab分配器

我们在上一讲已经讲到了

它将各种分配对象分组放进高速缓存中

也就是说每个高速缓存都对同类型分配对象的一种“储备”

如图所示是分区页框分配器

那么分区页框管理器分为两大部分

前端的管理区分配器和伙伴系统

管理区分配器

负责搜索一个能满足请求页框大小的管理区

在每个管理区中具体的页框分配工作呢是由伙伴系统负责的

为了达到更好的系统性能呢

单个页框的申请工作呢

直接通过每CPU页框高速缓存来完成

下面我们来给出页框分配函数的关系图

内核中有六个稍有差别的函数和宏来请求页框

那么图中四个绿色和两个蓝色来表示这六个函数

它们将核心的分配函数

也就是最底层的那个函数__alloc_pages_nodemask进行分装

从而形成满足不同分配需求的分配函数

那么通过上面的介绍我们来一个总结

从用户态到内核态的内存分配过程

当用户程序通过系统调用

申请内存的时候首先陷入内核

建立虚拟内存空间的映射

获得一块虚拟内存区VMA

当进程对这块虚存区进行访问的时候呢

如果物理内存尚未分配

那么此时发生一个缺页异常

通过get_free_page申请一个或者多个物理页面

并将此物理内存和虚拟内存的映射关系写入页表

通过前面的介绍我们对物理内存的分配过程呢

进行了一个比较系统的介绍

那么这个介绍还依然是比较简单的

如果要深入了解的话 我们需要看相关的参考资料

那么同样的我们需要查看《深入理解Linux内核》的第三版的第八章

还有http://edsionte.com/techblog/本博客中

“内存管理那些事儿”这个栏目里呢

有比较详细的关于内存管理的系列文章

同样呢我们来带着思考离开

在物理内存为1G的计算机中呢

能否malloc(1.6G)呢 那么

我们要给出“能”是为什么 “不能”为什么

本讲呢我们就讲到这里

谢谢大家

Linux 内核分析与应用课程列表:

第1章 概述

-1.1 Linux操作系统概述

--1.1 Linux 操作系统概述

-1.2 Linux内核结构以及内核模块编程

--Video

-1.3 Linux内核源码中的双链表结构

--Video

-1.4 源码分析-内核中的哈希表

--Video

-1.5 动手实践-Linux内核模块的插入和删除

--Video

-第1章 概述--章节测验

-第1章导学--引领你进入Linux内核的大门

第2章 内存寻址

-2.1 内存管理之内存寻址

--Video

-2.2 段机制

--Video

-2.3分页机制

--Video

-2.4 动手实践-把虚拟地址转换成物理地址

--Video

-第2章 内存寻址--章节测验

-第二章导学-从零打造自己的操作系统

第3章 进程管理

-3.1 进程概述

--Video

-3.2 Linux进程创建

--Video

-3.3 Linux进程调度

--Video

-3.4 动手实践-打印进程描述符task_struct中的字段

--Video

-3.5工程实践-基于内核模块的负载监控

--Video

-第3章 进程管理--章节测验

-第三章导学-进程背后琳琅满目的宝贝到哪里挖?

第4章 内存管理

-4.1 Linux内存管理机制

--Video

-4.2 进程用户空间管理机制

--Video

-4.3 物理内存分配与回收机制(上)

--Video

-4.4 物理内存分配与回收机制(下)

--Video

-4.5 动手实践-Linux内存映射基础(上)

--Video

-4.6 动手实践-Linux内存映射实现(中)

--Video

-4.7 动手实践-Linux内存映射测试(下)

--Video

-4.8 初学者对内存管理的常见疑惑

--初学者对内存管理的常见疑惑(一)

--初学者对内存管理的常见疑惑(二)

--初学者对内存管理的常见疑惑(三)

-第4章 内存管理--章节测验

第5章 中断

-5.1 中断机制概述

--Video

-5.2 中断处理机制

--Video

-5.3 中断下半部处理机制

--Video

-5.4 时钟中断机制

--Video

-5.5 动手实践-中断上半部的代码分析及应用

--Video

-5.6 动手实践-中断下半部的代码分析及应用

--Video

-第5章 中断--章节测验

第6章 系统调用

-6.1 Linux中的各种API

--Video

-6.2 系统调用机制

--Video

-6.3 动手实践-添加系统调用(系统调用日志收集系统)

--Video

-第6章 系统调用--章节测验

第7章 内核同步

-7.1 内核同步概述

--Video

-7.2 内核同步机制

--Video

-7.3 动手实践-内核多任务并发实例(上)

--Video

-7.4 动手实践-内核多任务并发实例(下)

--Video

-第7章 内核同步--章节测验

第8章 文件系统

-8.1 虚拟文件系统的引入

--Video

-8.2 虚拟文件系统的主要数据结构

--Video

-8.3 文件系统中的各种缓存

--Video

-8.4 页高速缓存机制以及读写

--Video

-8.5 动手实践-编写一个文件系统(上)

--Video

-8.6 动手实践-编写一个文件系统(中)

--Video

-8.7 动手实践-编写一个文件系统(下)

--Video

-第8章 文件系统--章节测验

第9章 设备驱动

-9.1 设备驱动概述

--Video

-9.2 I/O空间管理

--Video

-9.3 设备驱动模型

--Video

-9.4 字符设备驱动程序简介

--Video

-9.5 块设备驱动程序简介

--Video

-9.6 动手实践-编写字符设备驱动程序

--Video

-9.7工程实践-编写块设备驱动的基础(上)

--Video

-9.8 工程实践-块设备驱动程序分析(中)

--Video

-9.9 工程实践-块设备驱动程序实现(下)

--Video

-第9章 设备驱动--章节测验

致谢与说明

-致谢与说明

--Video

直播视频:从Linux内核学习到自主操作系统研发

-从Linux内核学习到自主操作系统研发

附录:实验代码、课件以及相关素材

-各章实验代码

-《Linux内核分析与应用》课件

-《Linux操作系统原理与应用》教材课堂视频

Video笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。