今天还有时间,之前一直想抽时间来写写Linux内核原理相关的东西,关注点不在代码,而在于内在的原理和机制,让大家对Linux内核有个总体的感性认识,个人认为这很有必要,把看似复杂、深不可测的内核实现,用大家都能理解的方式,用讲故事的方式,讲给大家听,如果有人听后,有原来不过如此的感觉,那我的目的就达到了。

# 内存管理

从哪里开始呢?还是从最基础的内存管理开始吧。

内存管理是Linux内核中最基础,也是相当重要的部分。理解相关原理,不管是对内存的理解,还是对大家写用户态代码都很有帮助。很多书上、很多文章都写了相关内容,但个人总觉得内容太复杂,不是太容易理解,这里想用我自己理解的简单的方式来描述,希望能有所帮助,按自己的思路,可能有点乱,见谅。

从内存分配开始

大家写代码时,应该都会分配内存,不同语言,层次不同,使用的接口不同,不管使用哪种方式,在Linux系统中,基本上都会调用到C库的malloc接口,那就从malloc分配内存开始。

malloc就是用于分配一段内存,但这里分配到的内存并非物理内存,而是虚拟内存,这里没有严格区分虚拟地址、线性地址之类的概念,只会给大家添负担,也不深入讲述物理内存和虚拟内存的概念,书上通常有大量的篇幅介绍,大家可以简单这样理解:

  • 虚拟内存就是从进程的角度看,逻辑上的概念,并不实际存在;

  • 物理内存就对应物理上内存条上的内存;

  • 虚拟内存和物理内存有对应关系;
  • 虚拟内存分配时,相应的物理内存还没有分配;

既然虚拟内存并不实际存在,那么分配来有何用处呢,如果要向其中写数据,数据如何写入呢?会写到哪里去呢?

当然,内存分配后就是拿来用的,如果不能用(比如写数据),那就没有意义了。前面说的虚拟内存和物理内存有对应关系,当分配虚拟内存时,相应的物理内存还没有分配,这里有几个关键问题:

  1. 虚拟内存和物理内存的对应关系由谁来负责维护,如何对应?
  2. 物理内存何时分配?

虚拟内存到物理内存的映射

先来解答问题1。

由页表来建立虚拟内存到物理内存之间的映射关系。 页表是啥?

简单看,页表就是在内存中的一张表(不详细介绍页表的具体格式啥的,看书就可以了),可以简单看做一张hash表,记录的是虚拟地址和物理地址的对应关系,每个虚拟地址对应一个表项,通过这张表,就能将虚拟地址转换为物理地址,也就能建立虚拟内存到物理内存的映射关系了。

谁用页表?

页表有了,那谁来用呢?不可能是应用程序自己用吧,我写代码时好像从来都没见过页表?

当然,用户看到的只是虚拟地址(虚拟内存),其他的对用户都是透明的~

CPU中有个硬件单元,叫MMU(内存管理单元),页表就是给MMU硬件用的,MMU使用页表进行虚拟地址到物理地址的映射。也就是说,地址映射是由硬件完成的,软件(包括操作系统内核自身)都不管关心。

都说软件不用关心了,那我们为嘛还需要讲页表?

软件只是不用页表而且,但页表的创建和维护都是由软件(操作系统内核)负责的,也就是说我们(软件)创建虚拟内存和物理内存的映射关系,然后由硬件来自动进行地址映射(转换),我们不需要关心具体的转换过程。

前面说了,页表是在内存中,而页表是由软件创建的,那MMU如果知道页表到底在哪儿呢?

简单说,需要我们(软件)告诉它在哪儿,如何告诉?当然,写寄存器。CPU上有特别的寄存器(CR3),向其中写入页表的地址,MMU就知道了,然后硬件自己使用即可,我们就不管了。

有多少张页表?

看似一张页表就能完成所有的地址映射了?

当然不行,如果是这样,虚拟内存就没有什么必要存在了。

这里又涉及新概念了:进程,这是操作系统中最基础的概念,其实不“新”。

系统中,所有任务都是以进程方式运行的,每个进程都有自己的独立的虚拟地址空间,好像又说复杂了,简单说,就是每个进程都有自己的虚拟内存,独立代表,其他进程看不到自己的虚拟内存,那么就意味着,每个进程都需要独立的虚拟内存到物理内存的映射,就是说,每个进程都需要自己的页表。

所以,系统中有多少进程,就有多少张页表。

页表创建

前面说了,页表的创建和维护是由操作系统内核完成的,那何时创建页表呢?

如前面所说,每个进程都需要自己的页表,显然,页表需要在进程创建时建立。具体的创建过程和原理就不讲了。

页表的维护

如果维护页表?

当然,进程自己维护,如果维护?

拿前面的例子说,malloc分配虚拟内存后,并没有分配物理内存,也没有建立映射关系,没有修改页表,那到底什么时候,由谁来做映射?

答案是:“缺页异常”。

缺页异常

缺页异常(page fault)又是另一个专业术语,表面上看好像不好理解。

简单看,就是一个异常。什么是异常?这又是硬件上的概念了,具体看看书

简单说,就是硬件上的一种机制,当硬件检测到某种“不对”时,主动触发,然后会自动跳转到异常处理程序处理。异常跟中断类似,区别在于,中断是异步的,由外设触发;异常是同步的,由CPU自己触发;好像又扯远了。

缺页异常就是一种特定的异常,触发条件是:MMU检测到页表项(页表中的项~)不存在。

何时触发缺页异常?

MMU何时会去检测页表项?

当CPU需要访问某个虚拟地址时,比如向某个虚拟地址写数据(memset),需要将虚拟地址转换成物理地址,此时MMU就会自动去页表中找相应的页表项,如果发现此时相应的页表项(也就是虚拟地址到物理地址的映射关系)还不存在,那么就会自动从硬件层面触发缺页异常。

也就说,缺页异常是硬件自己触发的,条件是当需要访问某个虚拟地址,而该虚拟地址还没有相应的页表项时。

典型的场景就是,当malloc之后,对相应的虚拟地址执行memset操作。

缺页异常中干嘛?

缺页异常后,会跳转到相应的异常处理程序处理,该异常处理程序是内核中提前注册好的,其中要做的主要操作,就是:分配物理内存,然后修改相应进程的页表,建立该物理内存和虚拟内存的映射关系(页表项)。

当然,实际实现要复杂得多,这里不详细描述。

回头看看

再来重头捋一下内存分配过程:

  1. 用户态程序使用malloc接口,分配虚拟地址。
  2. 用户程序访问该虚拟地址,比如memset。
  3. 硬件(MMU)需要将虚拟地址转换为物理地址。
  4. 硬件读取页表。
  5. 硬件发现相应的页表项不存在,硬件自动触发缺页异常。
  6. 硬件自动跳转到page fault的处理程序(内核实现注册好)
  7. 内核中的page fault处理程序执行,在其中分配物理内存,然后修改页表(创建页表项)
  8. 异常处理完毕,返回程序用户态,继续执行memset相应的操作。

至此,虚拟内存和物理内存都分配完成,并完成映射。

另一个角度看,如果malloc分配内存后,一直不使用,那就一直不会分配物理内存,这种内存分配策略叫延迟分配,有其相应的好处,自己理解一下~

接下来?

本章,从内存分配的角度看了Linux内核中内存管理的关键原理,已经以尽量简单的方式描述了,希望没给大家带来负担~

Linux内存管理还涉及其他很多方面,如:

  • 内核自身使用的内存(slab、vmalloc)
  • 伙伴系统
  • 进程地址空间管理

后面抽空慢慢讲,但都希望能尽量简单,希望大家一看就明白。

原文地址: http://happyseeker.github.io/kernel/2016/11/10/memory-management-in-kernel.html

闲聊Linux内存管理(1)相关推荐

  1. Windows内存管理和linux内存管理

    windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或 ...

  2. 万字长文,别再说你不懂Linux内存管理了(合辑),30 张图给你安排的明明白白...

    之前写了两篇详细分析 Linux 内存管理的文章,读者好评如潮.但由于是分开两篇来写,而这两篇内容其实是有很强关联的,有读者反馈没有看到另一篇读起来不够不连贯,为方便阅读这次特意把两篇整合在一起,看这 ...

  3. 别再说你不懂Linux内存管理了,10张图给你安排的明明白白!

    来自:后端技术学堂 过去的一周有点魔幻,有印象的有三个新闻:天猫总裁绯闻事件,蘑菇街裁员,不可能打工的周某也放出来了.三件事,两件和互联网行业相关,好像外面的世界很是精彩啊!吃瓜归吃瓜,学习还是不能落 ...

  4. Linux内存管理原理【转】

    转自:http://www.cnblogs.com/zhaoyl/p/3695517.html 本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址 ...

  5. Linux内存管理【转】

    转自:http://www.cnblogs.com/wuchanming/p/4360264.html 转载:http://www.kerneltravel.net/journal/v/mem.htm ...

  6. Linux内存管理之高端内存映射

    一:引子 我们在前面分析过,在linux内存管理中,内核使用3G->4G的地址空间,总共1G的大小.而且有一部份用来做非连续空间的物理映射(vmalloc).除掉这部份空间之外,只留下896M大 ...

  7. Linux内存管理原理

    本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址又叫线性地址.linux没有采用分段机制,所以逻辑地址和虚拟地址(线性地址)(在用户态,内核态逻 ...

  8. Linux内存管理 (2)页表的映射过程

    专题:Linux内存管理专题 关键词:swapper_pd_dir.ARM PGD/PTE.Linux PGD/PTE.pgd_offset_k. Linux下的页表映射分为两种,一是Linux自身的 ...

  9. Linux内存管理 (4)分配物理页面

    专题:Linux内存管理专题 关键词:分配掩码.伙伴系统.水位(watermark).空闲伙伴块合并. 我们知道Linux内存管理是以页为单位进行的,对内存的管理是通过伙伴系统进行. 从Linux内存 ...

最新文章

  1. 算法导论 第二部分——排序和顺序统计量
  2. Microsoft SQL Server 2005 安装程序错误解疑
  3. OpenCV:使用OpenCV3随机森林进行统计特征多类分析
  4. intellij选择困难症Spring Batch/Data JPA/Integration/MVC/Security/Web Flow/Web Services到底选哪个?
  5. 服务器 独立显卡 显示不出来,dell服务器R720+独立显卡GTX1650,进不去系统,UEIF报错...
  6. 白板机器学习笔记 P36-P38核方法
  7. 火神山医院完工,2月3日收治病人!“云监工”请放心!
  8. 关于hadoop2.4.1伪分布式系统的搭建
  9. sql测验,like 和 = 的区别
  10. 汉语转拼音和五笔简码
  11. 人工智能——状态空间的启发式搜索
  12. cannot retry due to redirection, in streaming mode
  13. php 获取支付宝账号密码,php支付宝单笔转账到支付宝账户,用户提现业务-Go语言中文社区...
  14. iOS 改变图片颜色
  15. 网易2017校园招聘笔试题 跳石板
  16. Toward Fast, Flexible, and Robust Low-Light Image Enhancement(实现快速、灵活和稳健的弱光图像增强)CVPR2022
  17. anymie360.exe,anymie360.dll,b770ca2.sys,Beep.sys,msiffei.sys等1
  18. mysql 数据导出导入
  19. OMA Download
  20. 很不错的刷Alexa排名的网站(转)

热门文章

  1. 多线程中Local Store Slot(本地存储槽)[转]
  2. [Servlet]深入掌握Servlet
  3. 关于ASP.NET MVC的业务逻辑验证(validation)
  4. 编译Qt“NMAKE:fatal error U1077”错误的解决方法
  5. 【Python】find()函数居然还能指定搜索的起点和终点?
  6. ustc小道消息20211227
  7. [云炬python3玩转机器学习] 6-1什么是梯度下降法
  8. 科大星云诗社动态20201227
  9. 云炬随笔20211011
  10. 学长毕业日记 :本科毕业论文写成博士论文的神操作20170314