【原创】(四)Linux内存模型之Sparse Memory Model
背景
Read the fucking source code!--By 鲁迅A picture is worth a thousand words.--By 高尔基
说明:
- Kernel版本:4.14
- ARM64处理器,Contex-A53,双核
- 使用工具:Source Insight 3.5, Visio
1. 介绍
顺着之前的分析,我们来到了bootmem_init()函数了,本以为一篇文章能搞定,大概扫了一遍代码之后,我默默的把它拆成了两部分。
bootmem_init()函数代码如下:
void __init bootmem_init(void)
{
unsigned long min, max;
min = PFN_UP(memblock_start_of_DRAM());
max = PFN_DOWN(memblock_end_of_DRAM());
early_memtest(min << PAGE_SHIFT, max << PAGE_SHIFT);
max_pfn = max_low_pfn = max;
arm64_numa_init();
/*
* Sparsemem tries to allocate bootmem in memory_present(), so must be
* done after the fixed reservations.
*/
arm64_memory_present();
sparse_init();
zone_sizes_init(min, max);
memblock_dump_all();
}
这一部分,我们将研究一下Sparse Memory Model。
在讲Linux内存模型之前,需要补充两个知识点:PFN和NUMA。
1.1 physical frame number(PFN)
前面我们讲述过了虚拟地址到物理地址的映射过程,而系统中对内存的管理是以页为单位的:
page:线性地址被分成以固定长度为单位的组,称为页,比如典型的4K大小,页内部连续的线性地址被映射到连续的物理地址中;
page frame:内存被分成固定长度的存储区域,称为页框,也叫物理页。每一个页框会包含一个页,页框的长度和一个页的长度是一致的,在内核中使用struct page来关联物理页。
如下图,PFN从图片中就能看出来了:

至于__page_to_pfn这个实现取决于具体的物理内存模型,下文将进行介绍。
1.2 NUMA
UMA: Uniform Memory Access,所有处理器对内存的访问都是一致的:

从上图中可以看出,当处理器和Core变多的时候,内存带宽将成为瓶颈问题。
NUMA: Non Uniform Memory Access,非一致性内存访问:

从图中可以看出,每个CPU访问local memory,速度更快,延迟更小。当然,整体的内存构成一个内存池,CPU也能访问remote memory,相对来说速度更慢,延迟更大。目前对NUMA的了解仅限于此,在内核中会遇到相关的代码,大概知道属于什么范畴就可以了。
2. Linux内存模型
Linux提供了三种内存模型(include/asm-generic/memory_model.h):

一般处理器架构支持一种或者多种内存模型,这个在编译阶段就已经确定,比如目前在ARM64中,使用的Sparse Memory Model。
Flat Memory
物理内存地址连续,这个也是Linux最初使用的内存模型。当内存有空洞的时候也是可以使用这个模型,只是struct page *mem_map数组的大小跟物理地址正相关,内存有空洞会造成浪费。Discontiguous Memory
物理内存存在空洞,随着Sparse Memory的提出,这种内存模型也逐渐被弃用了。Sparse Memory
物理内存存在空洞,并且支持内存热插拔,以section为单位进行管理,这也是下文将分析的。
Linux三种内存模型下,struct page到物理page frame的映射方式也不一样,具体可以查看include/asm-generic/memory_model.h文件中的__pfn_to_page/__page_to_pfn定义。
关于内存模型,可以参考Memory: the flat, the discontiguous, and the sparse
3. Sparse Memory
本节分析的是ARM64, UMA(linux4.14中不支持ARM NUMA)下的Sparse Memory模型。
3.1 mem_section
在Sparse Memory模型中,section是管理内存online/offline的最小内存单元,在ARM64中,section的大小为1G,而在Linux内核中,通过一个全局的二维数组struct mem_section **mem_section来维护映射关系。
函数的调用过程如下所示,主要在arm64_memory_present中来完成初始化及映射关系的建立:

函数调用结束之后的映射关系如下图所示:

已知一个pfn时,可以通过__pfn_to_section(pfn)来最终找到对应的struct page结构。
3.2 sparse_init
看看sparse_init函数的调用关系图:

在该函数中,首先分配了usermap,这个usermap与内存的回收机制相关,用4bit的bitmap来描述page block(一个pageblock大小通常为2的次幂,比如MAX_ORDER-1)的迁移类型:
/* Bit indices that affect a whole block of pages */
enum pageblock_bits {
PB_migrate,
PB_migrate_end = PB_migrate + 3 - 1,
/* 3 bits required for migrate types */
PB_migrate_skip,/* If set the block is skipped by compaction */
/*
* Assume the bits will always align on a word. If this assumption
* changes then get/set pageblock needs updating.
*/
NR_PAGEBLOCK_BITS
};
sparse memory模型会为每一个section都分配一个usermap,最终的物理页面的压缩,迁移等操作,都跟这些位相关,如下图所示:

sparse_init函数中,另一部分的作用是遍历所有present section,然后将其映射到vmemmap区域空间。vmemmap区域空间,在之前的文章中也提到过。执行完后,整体的效果如下图所示:

关于Sparse Memory Model就先分析这么多,只有结合使用sparse memory的具体模块时,理解才会更顺畅。
一不小心就容易扣细节,而一旦陷入细节,内核就容易变成魔鬼,太难了。

【原创】(四)Linux内存模型之Sparse Memory Model的更多相关文章
- JAVA内存模型(Java Memory Model ,JMM)
http://blog.csdn.net/hxpjava1/article/details/55189077 JVM有主内存(Main Memory)和工作内存(Working Memory),主内存 ...
- 并发研究之Java内存模型(Java Memory Model)
Java内存模型JMM java内存模型定义 上一遍文章我们讲到了CPU缓存一致性以及内存屏障问题.那么Java作为一个跨平台的语言,它的实现要面对不同的底层硬件系统,设计一个中间层模型来屏蔽底层的硬 ...
- 浅析java内存模型--JMM(Java Memory Model)
在并发编程中,多个线程之间采取什么机制进行通信(信息交换),什么机制进行数据的同步? 在Java语言中,采用的是共享内存模型来实现多线程之间的信息交换和数据同步的. 线程之间通过共享程序公共的状态,通 ...
- 并发编程之java内存模型(Java Memory Model ,JMM)
一.图例 0.两个概念 Heap(堆):运行时的数据区,由垃圾回收负责,运行时分配内存(所以慢),对象存放在堆上 如果两个线程,同时调用同一个变量,怎两个线程都拥有,该对象的私有拷贝 (可以看一下,T ...
- java内存模型(Java Memory Model)
内容导航: Java内存模型 硬件存储体系结构 Java内存模型和硬件存储体系之间的桥梁: 共享对象的可见性 竞争条件 Java内存模型规定了JVM怎样与计算机存储系统(RAM)协调工作.JVM是一个 ...
- Java 内存模型(Java Memory Model,JMM)
基本概念 JMM 本身是一种抽象的概念并不是真实存在,它描述的是一组规范,通过这组规范定义了程序的访问方式 JMM 同步规定 线程解锁前,必须把共享变量的值刷新回主内存 线程加锁前,必须读取主内存的最 ...
- 探索 Linux 内存模型--转
引用:http://www.ibm.com/developerworks/cn/linux/l-memmod/index.html 理解 Linux 使用的内存模型是从更大程度上掌握 Linux 设计 ...
- 【ARM-Linux开发】Linux内存管理:ARM Memory Layout以及mmu配置
原文:Linux内存管理:ARM Memory Layout以及mmu配置 在内核进行page初始化以及mmu配置之前,首先需要知道整个memory map. 1. ARM Memory Layout ...
- Linux内存模型
http://blog.csdn.net/sunyubo458/article/details/6090946 了解linux的内存模型,或许不能让你大幅度提高编程能力,但是作为一个基本知识点应该熟悉 ...
随机推荐
- Go中的日志及第三方日志包logrus
有别的语言使用基础的同学工作中都会接触到日志的使用,Go中自然也有log相关的实现.Go log模块主要提供了3类接口,分别是 "Print .Panic .Fatal ",对每一 ...
- [zz] pomelo windows 环境下开发环境搭建
原文链接:http://nodejs.netease.com/topic/515279a0b5a2705b5a000983 本文主要介绍下 windows 下跑通 pomelo 简单例子的过程 开发前 ...
- python调用支付宝支付接口详细示例—附带Django demo代码
项目演示: 一.输入金额 二.跳转到支付宝付款 三.支付成功 四.跳转回自己网站 在使用支付宝接口的前期准备: 1.支付宝公钥 2.应用公钥 3.应用私钥 4.APPID 5.Django 1.11. ...
- map redcue filter sorted函数
sorted 函数 接收一个key函数来实现自定义的排序 # 训练集和验证集的文件命名不一样 # test1: data/test1/8973.jpg # train: data/train/cat. ...
- spark任务调度模式,动态资源分配
官网链接: http://spark.apache.org/docs/latest/job-scheduling.html 主要介绍: 1 application级调度方式 2 单个applicati ...
- Redis的常用命令与Java整合及高级应用篇
一,redis是什么? 首先数据库分为关系型数据库和非关系型数据库,关系型数据库是采用关系模型来组织数据的数据库,简单来说就是二维表格模型,同时保证事务的一致性. 相反非关系型数据库采用key ...
- HBase 系列(五)——HBase 常用 Shell 命令
一.基本命令 打开 Hbase Shell: # hbase shell 1.1 获取帮助 # 获取帮助 help # 获取命令的详细信息 help 'status' 1.2 查看服务器状态 stat ...
- 基于CAS分析对ABA问题的一点思考
基于CAS分析对ABA问题的一点思考 什么是CAS? 背景 synchronized加锁消耗太大 volatile只保证可见性,不保证原子性 基础 用CPU提供的特殊指令,可以: 自动更新共享数据; ...
- ssh-key生成密钥及SSH无密码登录的配置
文章作者:foochane 原文链接:https://foochane.cn/article/2019061601.html 1 ssh-keygen命令 ssh-keygen命令说明: -t :指 ...
- 良许 | 命令的输出不会保存?居然连 tee 命令都不会用!
很多情况下,我们需要保存程序/命令的输出到本地,常用的一种方法是重定向,这也是一种很好的方法.但有个问题,如果你想要做后续操作,比如要统计输出的行数等,重定向就有困难了. 这时候,tee 命令就派上用 ...