物理内存的管理  

  Linux管理物理内存是使用分页机制实现的。为了使分页机制在32位和64位体系结构下高效工作,Linux采用了一个四级分页策略

  Linux支持多种内存分配机制。分配物理内存页框的主要机制是页面分配器,它使用了著名的伙伴算法作为物理内存分配机制。

  管理一块内存的基本思想如下。刚开始,内存由一块连续的片段组成,下图的简单例子是64个页面。当一个内存请求到达时,首先向上舍入到2的幂,比如8个页面。然后整个内存被分割成两半,如图b所示。因为这些片段还是太大了,较低的片段被再次二分(c),然后再二分(d)。现在我们有一块大小合适的内存,因此把它分配给请求者,如图d所示。

  

  现在假定8个页面的第二个请求到达了。这个请求有(e)直接满足了。此时4个页面的第三个请求到达了。最小可用的块被分割(f),然后其一半被分配(g)。接下来,8页面里的第二个块碑释放(h)。最后,8页面的另一个块也被释放。因为刚刚释放的两个邻接的8页面块来自同一个16页面块,它们合并起来得到一个16页面的块(i)。

虚拟地址空间 

  Linux为每个进程维持一个单独的虚拟地址空间。如下图所示。

  

  

  虚拟地址空间被分割成同构连续页面对齐的区域。也就是说,每个区域由一系列连续的具有相同保护和分页属性的页面组成。代码段、数据段、堆、共享库段以及用户栈都是不同的区域。每个存在的虚拟页面都保存在某个区域中,而不属于某个区域的虚拟也是不存在的。在虚拟地址空间的区之间可以有空隙。所有对这些空隙的引用都会导致一个严重的页面故障。

  在内核中,每个区是用vm_area_struct项来描述的。一个进程的所有vm_area_struct用一个链表连接在一起,并且按照虚拟地址排序以便可以找到所有的页面。当这个链表太长时(多于32项),就创建一个树来加速搜索。vm_area_struct项列出了该区的属性。这些属性包括:保护模式(如,只读或者可读可写),是否固定在内存中(不可换出)、朝向哪个方向生长(数据段向上,栈段向下)。

  vm_area_struct也记录了该区是私有的还是跟一个或多个其他进程共享的。fork之后,Linux为子进程复制一份区链表,但是为了让父子进程指向相同的也表。区标记为可读可写,但是页面却被标记为只读。如果任何一个进程试图写页面,就会产生一个保护故障,此时内核发现该内存区域逻辑上是可写的,但是页面却不是,因此它把该页面的一个副本给当前进程同时标记为可读可写。这个机制就说明了写时复制是如何实现的。

  vm_area_struct也记录了该区是否在磁盘上有备份存储,如果有,在什么地方。代码段把可执行二进制文件作为备份存储,内存映射文件把磁盘文件作为备份存储。其他区,如栈,直到它们不得不被换出,否则没有备份存储被分配。

  一个顶层内存描述符mm_struct收集属于一个地址空间的所有虚拟内存区相关的信息,还有关于不同段(代码、数据、栈)和用户共享地址空间的信息等。一个地址空间的所有vm_area_struct元素可以通过内存描述符用两种方式访问。首先,它们是按照虚拟地址顺序组织在链表中的。这种方式的有用之处是:当所有的虚拟地址区需要被访问时,或者当内核查找分配一个指定大小的虚拟内存区域时。此外,vm_area_struct项目被组织成二叉“红黑”树。这种方法用于访问一个指定的虚拟内存地址。为了能够用这两种方法访问进程地址空间的元素,Linux为每个进程使用了更多的状态,但是却允许不同的内核操作来使用这些访问状态,这对进程而言更加高效。

  下图强调了记录一个进程中虚拟存储器区域的内核数据结构。内核为系统中的每个进程维护一个单独的任务结构(源代码中的task_struct)。任务结构中的元素包含或者指向内核运行该进程所需要的所有信息(例如,PID,指向用户栈的指针、可执行目标文件的名字以及程序计数器)。

  

  task_struct中的一个条目指向mm_struct,它描述了虚拟存储器的当前状态。我们感兴趣的两个字段是pdg和mmap,其中pdf指向第一级页表(页全局目录)的基址,而mmap指向一个vm_area_struct(区域结构链表),其中每个vm_area_strcuts都描述了当前虚拟地址空间的一个区域(area)。当内核运行这个进程时,它就将pdf存放在CR3控制寄存器中。

  为了我们的目的,一个具体区域的区域结构包含下面的字段:

  vm_struct:指向这个区域的起始处。

  vm_end: 指向这个区域的结束处。

  vm_prot: 描述这个区域内包含的所有页的读写许可权限。

  vm_flags:描述这个区域内的页面是与其他进程共享的,还是这个进程私有的、

  vm_next: 指向链表中下一个区域结构。

虚拟地址空间到物理地址空间的映射

  虚拟存储的实现需要依靠硬件的支持,对于不同的CPU来说是不同的。但是几乎所有的硬件都采用一个MMU((Memmory Management Unit)的部件来进行映射,如下图所示。

  

  在页映射模式下,CPU发出的是Virtual Address, 即我们的程序看到的是虚拟地址。经过MMU转换以后就变成了Physical Address。一般MMU都集成在CPU内部了,不会以独立的部件存在。

参考资料:

  1. 《深入理解计算机系统》 (第二版)  机械工业出版社

  2. 《程序员的自我修养》

  3. 《现代操作系统》(原书第2版)  机械工业出版社

Linux是如何管理内存的的更多相关文章

  1. 性能测试必备知识(10)- Linux 是怎么管理内存的?

    做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 内存映射 日常生活常说的内存是什么 比方说, ...

  2. linux内核分析之内存管理

    1.struct page /* Each physical page in the system has a struct page associated with * it to keep tra ...

  3. 初探Linux内核中的内存管理

    Linux内核设计与实现之内存管理的读书笔记 初探Linux内核管理 内核本身不像用户空间那样奢侈的使用内存; 内核不支持简单快捷的内存分配机制, 用户空间支持? 这种简单快捷的内存分配机制是什么呢? ...

  4. [转载]linux段页式内存管理技术

    原始博客地址: http://blog.csdn.net/qq_26626709/article/details/52742470 一.概述 1.虚拟地址空间 内存是通过指针寻址的,因而CPU的字长决 ...

  5. Linux的虚拟内存管理-如何分配和释放内存,以提高服务器在高并发情况下的性能,从而降低了系统的负载

    Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和free是如何分配和释放内存?如何查看堆内内存的碎片情况?既然堆内内存brk和sbrk不能直接释放,为什么不全 ...

  6. Linux系统基本的内存管理知识讲解

    内存是Linux内核所管理的最重要的资源之一.内存管理系统是操作系统中最为重要的部分,因为系统的物理内存总是少于系统所需要的内存数量.虚拟内存就是为了克服这个矛盾而采用的策略.系统的虚拟内存通过在各个 ...

  7. <Linux内核源码>内存管理模型

    题外语:本人对linux内核的了解尚浅,如果有差池欢迎指正,也欢迎提问交流! 首先要理解一下每一个进程是如何维护自己独立的寻址空间的,我的电脑里呢是8G内存空间.了解过的朋友应该都知道这是虚拟内存技术 ...

  8. [内存管理]linux X86_64处理器的内存布局图

    linux X86 64位内存布局图

  9. java语言:Linux与JVM的内存关系分

    在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约 600m,Linux自身使用大约800m.从表面上,物理内存应该 ...

随机推荐

  1. PostgreSQL 中定义自己需要的数据类型

    PostgreSQL解决某系数据库中的tinyint数据类型问题,创建自己需要的数据类型如下: CREATE DOMAIN tinyint AS smallint CONSTRAINT tinyint ...

  2. JQuery下CheckBox全选全不选反选

    <script src="JS/jquery-1.7.1.js"></script> <script type="text/javascri ...

  3. [转] HashMap的工作原理

    HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如此 ...

  4. C++之路进阶——codevs1036(商务旅行)

    1036 商务旅行 题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇 ...

  5. Android so lib库远程http下载和动态注册

    一.背景 在开发Android应用程序的实现,有时候需要引入第三方so lib库,但第三方so库比较大,例如开源第三方播放组件ffmpeg库, 如果直接打包的apk包里面, 整个应用程序会大很多.经过 ...

  6. 动画--过渡所需时间 transition-duration

    transition-duration属性主要用来设置一个属性过渡到另一个属性所需的时间,也就是从旧属性过渡到新属性花费的时间长度,俗称持续时间. 案例演示: 在鼠标悬停(hover)状态下,让容器从 ...

  7. String.Format数字格式化参考

    String.Format数字格式化输出 {0:N2} {0:D2} {0:C2} (转) 数字 {0:N2} 12.36 数字 {0:N0} 13 货币 {0:c2} $12.36 货币 {0:c4 ...

  8. 使用streaming window函数统计用户不同时间段平均消费金额等指标

    场景 现在餐厅老板已经不满足仅仅统计历史用户消费金额总数了,他想知道每个用户半年,每个月,每天,或者一小时消费的总额,来店消费的次数以及平均金额. 给出的例子计算的是每5秒,每30秒,每1分钟的用户消 ...

  9. spark streaming - kafka updateStateByKey 统计用户消费金额

    场景 餐厅老板想要统计每个用户来他的店里总共消费了多少金额,我们可以使用updateStateByKey来实现 从kafka接收用户消费json数据,统计每分钟用户的消费情况,并且统计所有时间所有用户 ...

  10. Jquery文档接口遍历

    // children():获取所有子元素 <%@ page language="java" contentType="text/html; charset=utf ...