讲解复杂繁琐的机制原理,最通俗的方法就是用模型架构的方式向读者呈现,先要在整体上了解大方向大架构,再根据大方向大架构来进行分支深入,犹如毛主席那句话“战略上蔑视敌人,战术上重视敌人”。下面我也以这种方式把各个大模型方式向大家画出,并作出简略解述。

一.  地址划分。

  1. CPU地址。

  CPU地址是指CPU的地址总线能寻址的范围,32bit-CPU寻址范围为4G, 这个地址是虚拟的,实际上外部物理内存是不会使用这么大的内存。

  CPU虚拟地址的4G空间,通常划分为两部分,一部分为内核虚拟地址,通常为3G-4G之间,另一部分为用户虚拟地址,通常为0G-3G之间,显然,用户进程能使用的虚拟地址范围远大于内核可以使用的虚拟地址空间,但是,物理内存只有局限性的几M,几G,内核虚拟地址如何使用物理内存,用户空间如何使用物理内存,这些问题正是linux内存管理的关键。

  2.  物理内存

  物理内存是指外部存储数据的设备,有可以被CPU寻址到的地址总线,受到CPU的Cache 和TLB/MMU管理寻址。

  需要澄清一个概念:任何代码是在CPU上运行的,而不是在物理内存上,物理内存是个设备,用于存放用户进程空间的可执行代码或者内核关键数据结构,这些代码或结构终将是要受到CPU通过MMU寻址,Cache命中指令数据来获取的。

  NUMA的全称是非一致性内存访问,它通常是多核访问的概念,每一个CPU核都会有一个节点对应使用一部分物理内存,对这些节点的管理附加这些数据结构:perCPU变量,list表串联各节点遍历,zone的划分,zonelist的管理等等。为了使问题更加简单化,我们只分析UMA的一个节点的情况,当然它也包含NUMA的一些数据结构特征,这个后面会有所简述。

  下图是NUMA的一个简略图抽象如图2-1所示。

  

图2-1 NUMA多核物理内存zone示意图

  3.  内核虚拟地址空间划分。

  如果读者仅仅了解一些皮毛,必然认为内核的虚拟地址空间仅有逻辑地址这一说,其实这只是内存内核虚拟地址划分的一个特例,并非全部的完整表述,现在我划出完整的图形,并且改变改变对内核虚拟地址空间名称的叫法,如图2-2

   图2-2 内核虚拟地址空间划分及其对物理内存的映射

  下面来改改名字咯,直接映射的地址我们可以叫为内核物理直接映射地址或者逻辑地址。linux原则上只能使用虚拟空间1G中的896M,剩下的128M留作它用,所以直接映射之外的物理内存称为高端内存。128M之间的空间又划分为多个gap安全间隙,虚拟地址,固定映射和持久映射,注意这里的虚拟地址叫法通常和前述的内核虚拟地址有些混杂,后者是指CPU内核虚拟地址,是更广的概念。由于直接映射的部分有了名字叫逻辑地址,那么这里的虚拟地址空间常专指这个部分。

  虚拟地址有以下用途,使用vm_struct结构体经内核管理高端内存,它可以使用kmap方式获取高端物理内存的空间;也可以不映射物理高端内存,将这段地址直接作为外部物理设备的ioremap地址,从而可以直接操纵设备,当然这也将外部设备地址空间暴露出来并且容易造成干扰,所以通常不能直接访问ioremap映射的地址而是用readb/writeb读写,而且要做好优化屏障设置并且用iounmap释放,因为映射了的设备常具有’边际效应’.

  如果没有高端内存,(当然32bit的嵌入式系统通常不会使用高端内存,至少我见过的那么多关于ARM,powerPC,MIPS32的嵌入式应用都是没有使用高端内存的), 那么固定映射和持久映射也多半不会用到。固定映射可以指定长期持有物理内存某些地址页的占用,这个映射关系可以在初始阶段进行配置,而持久映射在启用时就建立了同高端内存物理页的映射关系,它在其他阶段都不会被解除。

  强调的是,我这里不关心高端内存,内核的直接映射逻辑地址就可以涵盖全部物理内存。

  4.  用户虚拟地址空间的划分

  用户虚拟地址空间图构并不复杂,复杂的是它在虚拟内存空间中的应用,如何映射文件,如何组织区间映射,关联的进程是谁,对应的内存结构体实例是什么等等问题才是用户虚拟映射最难的地方,下面仅仅划出图示,对用户虚拟内存空间可以先有一个大了解,如图2-3。

        

                           图2-3用户空间虚拟内存布局

   既然用户空间是虚拟的,那么它是怎么访问物理内存的呢,当然就是PGD,PUD,PMD,PTE,OFFSET及其TLB快表查询了,上层目录入口PUD和中间目录入口一般不考虑,考虑二级目录就可以了。从网上摘的图2-4:

        

图2-4 用户进程空间访问物理内存的方法

二.  伙伴系统

伙伴系统是按阶管理外界物理内存的方法,最大有11阶,每一阶有一个或者多个页合并的集合并使用指针串联起来,同时在同一阶中的一个或多个页集合中形成各自的伙伴,要强调的是各个阶的伙伴都是等页个数的,用下图2-5是比较好理解的。

        

    图2-5 伙伴系统在内存中的大致模型

  当内核申请一段按页却并非按照阶数分配的内存时候,通常会使用伙伴系统原理将其按照该申请空间的最大阶数分配,多出来的页按照伙伴系统算法归并到其他阶的链表当中形成其他阶的新伙伴。释放该内存空间的时候,释放的空间会尝试找到能以它为伙伴的那个阶进行连接,如果大小超过,则劈开,多余的再寻找其他可以以它为伙伴的阶。够拗口的,但还是很容易理解的,后面会有源代码呈现出来以实例详细分析。

三.  反碎片技术:

  反碎片机制其实还在伙伴系统之前,它主要是将各个zone区域的物理内存分成可回收reclaimable但不可移动unmovable,可移动movable,不可移动unmovable. 这些标记按照一定得list串联起来管理,当外部条件申请物理内存导致许多碎片的时候,它可以按照这些数据结构的标志,来从新组织归类物理内存,从而减少碎片页或者孤独页。反碎片技术在嵌入式系统当中少用,绝大部分由伙伴系统占据江山了,因此不会对此做具体分析,简略过之。

四.    Slab分配机制。

linux内存管理之全局框架的更多相关文章

  1. Linux内存管理的基本框架⭐⭐

    Linux内核的映射机制设计成三层,在页面目录和页面表中间增设了一层“中间目录”.在代码中,页面目录称为PGD,中间目录称为PMD,而页面表称为PT.PT中的表项称为PTE,PTE是“Page Tab ...

  2. Linux内存管理解析(二) : 关于Linux内存管理的大体框架

    什么是内存管理 ? 首先内存管理管理的主要对象是虚拟内存,但是虚拟内存对应的映射主要为物理内存,其次也可能通过交换空间把虚拟内存与硬盘映射起来,既然如此,那我们先了解物理内存的管理. 对于物理内存而言 ...

  3. linux 内核源代码情景分析——linux 内存管理的基本框架

    386 CPU中的页式存管的基本思路是:通过页面目录和页面表分两个层次实现从线性地址到物理地址的映射.这种映射模式在大多数情况下可以节省页面表所占用的空间.因为大多数进程不会用到整个虚存空间,在虚存空 ...

  4. 伙伴系统之避免碎片--Linux内存管理(十六)

    1 前景提要 1.1 碎片化问题 分页与分段 页是信息的物理单位, 分页是为了实现非连续分配, 以便解决内存碎片问题, 或者说分页是由于系统管理的需要. 段是信息的逻辑单位,它含有一组意义相对完整的信 ...

  5. 启动期间的内存管理之bootmem_init初始化内存管理–Linux内存管理(十二)

    1. 启动过程中的内存初始化 首先我们来看看start_kernel是如何初始化系统的, start_kerne定义在init/main.c?v=4.7, line 479 其代码很复杂, 我们只截取 ...

  6. 启动期间的内存管理之初始化过程概述----Linux内存管理(九)

    在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检 ...

  7. Linux内存管理(一)

    Linux内存管理之一:基本概念篇 物理地址.线性地址(虚拟地址)和逻辑地址:阐述段式管理和页式管理基本概念:Linux操作系统内存管理和虚拟内存概念:为内核开发做一个基础铺垫. 内存是linux内核 ...

  8. 转 Linux内存管理原理

    Linux内存管理原理 在用户态,内核态逻辑地址专指下文说的线性偏移前的地址Linux内核虚拟3.伙伴算法和slab分配器 16个页面RAM因为最大连续内存大小为16个页面 页面最多16个页面,所以1 ...

  9. 面试问了解Linux内存管理吗?10张图给你安排的明明白白!

    文章每周持续更新,各位的「三连」是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 今天来带大家研究一下Linux内存管理.对于精通 CURD 的业务同学 ...

随机推荐

  1. 让你的 CDN 费用省 50% 以上!图片瘦身的正确姿势

    七牛云新推出的图片瘦身功能是做什么的? 打开七牛云的「数据处理」中的「图片瘦身」功能,在图片受到访问时,能够实时对图片进行瘦身,在保证分辨率和画质不变的情况下,可以将图片最高缩小 80%.当「图片瘦身 ...

  2. 公路修建(Prim)

    洛谷传送门 这道水题告诉了我,堆优化的prim有时还不如朴素prim快... 居然记错时间复杂度了,我也真是菜. #include <cstdio> #include <queue& ...

  3. docker持续集成部署、csphere监控平台【转:http://blog.csdn.net/java_dyq/article/details/51997024】

    为什么使用Docker “ 从我个人使用的角度讲的话  部署来的更方便 只要构建过一次环境 推送到镜像仓库 迁移起来也是分分钟的事情 虚拟化让集群的管理和控制部署都更方便 hub.docker.com ...

  4. putty 配置

    http://blog.sanctum.geek.nz/putty-configuration/ PuTTY configuration Posted on December 22, 2012 PuT ...

  5. Codeforces 660E Different Subsets For All Tuples【组合数学】

    看了官方题解+q神的讲解才懂... 智商问题.. 讲道理..数学真的比脱单难啊... 题目链接: http://codeforces.com/problemset/problem/660/E 题意: ...

  6. 洛谷 P3807 【模板】卢卡斯定理

    P3807 [模板]卢卡斯定理 题目背景 这是一道模板题. 题目描述 给定n,m,p(1\le n,m,p\le 10^51≤n,m,p≤105) 求 C_{n+m}^{m}\ mod\ pCn+mm ...

  7. Eclipse同时显示多个控制台项目的输出

    操作步骤: 1.运行项目1,运行项目2 2.在Exlipse中选择这两个的控制台进行切换

  8. 还原数据库出现“未获得排他訪问”解决方法(杀死数据库连接的存储过程sqlserver)

    在master数据库下创建存储步骤例如以下: createproc killspid (@dbnamevarchar(20)) as begin declare@sqlnvarchar(500) de ...

  9. 【APUE】进程基础

    进程标识符:非负整数 ID为0的进程通常是是调度进程,常被称为交换进程.该进程是内核的一部分,它并不执行任何磁盘上的程序,因此也被称为系统进程 ID为1的进程是init进程,在自举过程结束时由内核调用 ...

  10. 【c++】动态内存

    静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.它主要存放静态数据.全局数据和常量.注意:const常量在定义时必须初始化 栈区:在执行函数时,函数内局部变量的存储单 ...