Linux的内存管理涉及到的内容非常庞杂,而且与内核的方方面面耦合在一起,想要理解透彻非常困难。

在开始学习之前进行了一些准备工作《如何展开Linux Memory Management学习?》,

1. 参考资料

遂决定以如下资料作为参考,进行Linux内存管理的研究:

奔跑吧 Linux内核》:以第2章为蓝本展开,这是目前能获取的紧跟当前内核发展(Linux 4.0),并且讲的比较全面的一本资料。

Understanding the Linux Virtual Memory Manager》:简单说就是虽老但经典,基于(Linux 2.4/2.6)。作者是目前仍然活跃在Linux社区MM专家。

wowotech Memory Management》:没有其他系列经典,也没有条理系列的介绍MM,但是仍然值得按考。

tolimit Linux内存源码分析》:相对零散的介绍了内存相关分析文档

Linux Kernel v4.0》:当然必不可少的,是源码了。

当逐渐深入看到MMU相关代码时,读一下ARM架构关于MMU的规格书有助于理解。

不然对于虚拟地址到物理地址的映射就会很虚无,这些资料包括《ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition》的《Virtual Memory System Architecture》,以及相关MMU TRM。

2. Linux Memory Management框架图

整个内存管理从宏观上可以分为三大部分:用户空间、内核空间和相关硬件

用户空间主要是libc对相关系统调用进行封装,对用户程序提供API,常用的有malloc、mmap、munmap、remap、madvise、mempolicy等等。

相关硬件包括MMU/TLB、L1/L2 Cache以及DDR RAM,具体到ARM架构需要对照MMU/L2 Cache以及RAM规格书。

内核空间就复杂多了,首先介绍初始化及初始化后的布局。

2.1 物理内存初始化从获取内存大小、初始化页表,再进行zone初始化,然后在zone中使用伙伴系统进行物理内存初始化;

2.2 页表的映射过程讲述了ARM32和ARM64两种架构下的页表映射,如何从虚拟地址由MMU转化成物理页面地址的;

2.3 内核内存的布局图在内存被初始化之后,内核的内存布局基本上就确定了,ARM32和ARM64下布局有很大区别。在malloc一节brk中介绍了用户空间的布局。

2.1~2.3是内存的一个静态状态,在有了这些基础之后,2.4~2.9按照从低层到上层的逐个介绍了。

2.4 分配物理页面介绍了基于伙伴系统的页分配和释放;

2.5 slab分配器基于伙伴系统,slab分配更小内存块;以及基于slab的kmalloc;

2.6 vmalloc和kmalloc区别在于v,即在VMALLOC区域分配;

2.7 VMA即Virtual Memory Area,是进程内存管理的核心;

2.8 malloc2.9 mmap都基于VMA,malloc/free用于分配/释放一块内存;mmap/munmap用于匿名/文件映射到用户空间。以及mmap(补充)

由于malloc/mmap分配内存并不是立即分配,只是在用到的时候才会触发2.10 缺页中断处理

在缺页但页不足的情况下,就需要进行一些操作调整内存,这些操作的基础是2.11 page引用计数,还有页面的2.12 反向映射RMAP技术。

在内存不足情况下触发kswapd2.13 回收页面,其中匿名页面有着特殊的2.14 匿名页面生命周期

在kswapd回收依然无法满足内存分配,就需要对内存进行2.16 内存规整,它依赖的技术是2.15 页面迁移

由于内存中存在一些内容完全一样的页面,使用2.17 KSM技术进行合并,同时利用COW技术,在需要时重新分配。

还介绍了2.18 Dirty COW内存漏洞,然后对内存管理数据结构和API进行了总结2.19 总结内存管理数据结构和API

最后2.20 最新更新和展望对新技术进行了介绍。

除了以上技术,还有如下内存技术:

  • swap计数把匿名页面写入SWAP分区从而释放出空闲页面
  • 内存压缩技术zram(a compressed RAM based swap device)
  • zswap技术是zram和swap的一个综合,首先将待换出页面进行压缩,存储到系统RAM动态分配的内存池中;达到一定阈值后再写入实际交换设备。
  • 在内存极端不足情况下使用21OOM(Out-Of-Memory)来杀死不重要进程获取更多内存的技术
  • 基于cgroup的Memory资源控制
  • 解决多媒体对大量连续内存需求的CMA(Contiguous Memory Allocator)技术
  • slub分配器
  • memory hotplug内存热插拔支持动态更换内存物理设备

==============================================================================================================================

在对内存相关技术了解过后,就是如何运用的问题了?

一方面是对内存问题进行定位;另一方面是对内存行为施加影响,进行优化。

22 内存检测技术对Linux内存常见问题及其定位方法和工具(slub_debug/kmemleak/kasan)进行了讲解。

23 一个内存Oops解析以一个内存Oops为例,介绍了内存相关异常分析。

内存sysfs节点和工具介绍了linux内存管理相关sysfs节点,以及工具;借助这些可以对内存进行优化。

扩展阅读:

Linux内存管理框架图

3. 代码和测试环境搭建

3.1 QEMU

安装QEMU以及相关编译工具

sudo apt-get install qemu libncurses5-dev gcc-arm-linux-gnueabi build-essential

3.2 Busybox 1.24

下载Busybox 1.24代码:

git clone https://github.com/arnoldlu/busybox.git -b 1_24_stable

编译Busybox:

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
#make menuconfig #P684,进行配置
make -j4 install

配置initramfs:

sudo cp -r running_kernel_initramfs/* _install/
sudo chmod +x _install/etc/init.d/rcS
cd _install
mkdir mnt
mkdir dev
cd dev
sudo mknod console c 5 1
sudo mknod null c 1 3

3.3 Kernel 4.0

下载Linux Kernel 4.0代码:

git clone https://github.com/arnoldlu/linux.git -b running_kernel_4.0

编译Linux Kernel:

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make vexpress_defconfig #P685进行配置
make bzImage -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
make dtbs

3.4 运行内核

#Run Kernel+Busybox in QEMU
qemu-system-arm -M vexpress-a9 -smp 4 -m 1024M -kernel arch/arm/boot/zImage -append "rdinit=/linuxrc console=ttyAMA0 loglevel=8" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic

至此,已经有一个完整的环境,提供shell命令。

4. 思考问答

  1. 在系统启动时,ARM Linux内核如何知道系统中有多大的内存空间?
  2. 在32bit Linux内核中,用户空间和内核空间的比例通常是3:1,可以修改成2:2吗?
  3. 物理内存页面如何添加到伙伴系统中,是一页一页添加,还是以2的几次幂来加入呢?
  4. 内核的一级页表存放在什么地方?二级页表又存放在什么地方?
  5. 用户进程的一级页表存放在什么地方?二级页表呢?
  6. 在ARM32系统中,页表是如何映射的?在ARM64系统中,页表又是如何映射的?
  7. 请简述Linux内核在理想情况下页面分配器(page allocator)是如何分配出连续物理页面的。
  8. 在页面分配器中,如何从分配掩码(gfp_mask)中确定可以从哪些zone中分配内存?
  9. 页面分配器是按照什么方向来扫描zone的?
  10. 为用户进程分配物理内存,分配掩码应该选用GFP_KERNEL,还是GFP_HIGHUSER_MOVABLE呢?
  11. slab分配器是如何分配和释放小块内存的?
  12. slab分配器中有一个着色的概念(cache color),着色有什么作用?
  13. slab分配其中的slab对象有没有根据Per-CPU做一些优化?
  14. slab增长并导致大量不用的空闲对象,该如何解决?
  15. 请问kmalloc、vmalloc和malloc之间有什么区别以及实现上的差异?
  16. 使用用户态的API函数malloc()分配内存时,会马上为其分配物理内存吗?
  17. 假设不考虑libc的因素,malloc分配100Byte,那么实际上内核是为其分配100Byte吗?
  18. 假设两个用户进程打印的malloc()分配的虚拟地址是一样的,那么在内核中这两块虚拟内存是否打架了呢?
  19. vm_normal_page()函数返回的是什么样页面的struct page数据结构?为什么内存管理代码中需要这个函数?
  20. 请简述get_user_page()函数的作用和实现流程?
  21. 请简述follow_page()函数的作用和实现流程?
  22. 请简述私有映射和共享映射的区别。
  23. 为什么第二次调用mmap时,Linux内核没有捕捉到地址重叠并返回失败呢?
  24. struct page数据结构中的_count和_mapcount有什么区别?
  25. 匿名页面和page cache页面有什么区别?
  26. struct page数据结构中有一个锁,请问trylock_page()和lock_page()有什么区别?
  27. 在Linux 2.4.x内核中,如何从一个page找到所有映射该页面的VMA?反响映射可以带来哪些便利?
  28. 阅读Linux 4.0内核RMAP机制的代码,画出父子进程之间VMA、AVC、anon_vma和page等数据结构之间的关系图。
  29. 在Linux 2.6.34中,RMAP机制采用了新的实现,在Linux 2.6.33和之前的版本中称为旧版本RMAP机制。那么在旧版本RMAP机制中,如果父进程有1000个子进程,每个子进程都有一个VMA,这个VMA里面有1000个匿名页面,当所有的子进程的VMA同时发生写复制时会是什么情况呢?
  30. 当page加入lru链表中,被其他线程释放了这个page,那么lru链表如何知道这个page已经被释放了。
  31. kswapd内核线程何时会被唤醒?
  32. LRU链表如何知道page的活动频繁程度?
  33. kswapd按照什么原则来换出页面?
  34. kswapd按照什么方向来扫描zone?
  35. kswapd以什么标准来退出扫描LRU?
  36. 手持设备例如Android系统,没有swap分区或者swap文件,kswapd会扫描匿名页面LRU吗?
  37. swappiness的含义是什么?kswapd如何计算匿名页面和page cache之间的扫描比重?
  38. 当系统充斥着大量只访问一次的文件访问(use-one streaming IO)时,kswapd如何来规避这种风暴?
  39. 在回收page cache时,对于dirty的page cache,kswapd会马上回写吗?
  40. 内核有哪些页面会被kswapd写回交换分区?
  41. ARM32 Linux如何模拟这个Linux版本的L_PTE_YOUNG比特位呢?
  42. 如何理解Refault Distance算法?
  43. 请简述匿名页面的生命周期。在什么情况下会产生匿名页面?在什么条件下会释放匿名页面?
  44. KSM是基于什么原理来合并页面的?
  45. 在KSM机制里,合并过程中把page设置成写保护的函数write_protect_page()有这样一个判断:。这个判断的依据是什么?
  46. 如果多个VMA的虚拟页面同时映射了同一个匿名页面,那么此时page->index应该等于多少?
  47. 为什么Dirty COW小程序可以修改一个只读文件的内容?
  48. 在Dirty COW内存漏洞中,如果Diryt COW程序没有madviseThread线程,即只有procselfmemThread线程,能否修改foo文件的内容呢?
  49. 假设在内核空间获取了某个文件对应的page cache页面的struct page数据结构,而对应的VMA属性是只读,那么内核空间是否可以成功修改该文件呢?
  50. 如果用户进程使用只读属性(PROT_READ)来mmap映射一个文件到用户空间,然后使用memcpy来写这段内存空间,会是什么样的情况?
  51. 请画出内存管理中常用的数据结构的关系图,如mm_struct、vma、vaddr、page、pfn、pte、zone、paddr和pg_data等,并思考如下转换关系。
  52. 请画出在最糟糕的情况下分配若干个连续物理页面的流程图。
  53. 在Android中新添加了LMK(Low Memory Killer),请描述LMK和OOM Killer之间的关系。
  54. 请描述一致性DMA映射dma_alloc_coherent()函数在AEM中是如何管理cache一致性的?
  55. 请描述流式DMA映射dma_map_single()函数在ARM中是如何管理cache一致性的?
  56. 为什么在Linux 4.8内核中要把基于zone的LRU链表机制迁移到基于Node呢?

Linux内存管理专题的更多相关文章

  1. Linux内存管理 (5)slab分配器

    专题:Linux内存管理专题 关键词:slab/slub/slob.slab描述符.kmalloc.本地/共享对象缓冲池.slabs_partial/slabs_full/slabs_free.ava ...

  2. Linux内存管理 (1)物理内存初始化

    专题:Linux内存管理专题 关键词:用户内核空间划分.Node/Zone/Page.memblock.PGD/PUD/PMD/PTE.lowmem/highmem.ZONE_DMA/ZONE_NOR ...

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

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

  4. Linux内存管理 (3)内核内存的布局图

    专题:Linux内存管理专题 关键词:内核内存布局图.lowmem线性映射区.kernel image.ZONE_NORMAL.ZONE_HIGHMEM.swapper_pg_dir.fixmap.v ...

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

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

  6. Linux内存管理 (6)vmalloc

    专题:Linux内存管理专题 关键词:vmalloc.页对齐.虚拟地址连续.物理不连续 至此,已经介绍了集中内核中内存分配函数,在开始简单做个对比总结Linux中常用内存分配函数的异同点,然后重点介绍 ...

  7. Linux内存管理 (7)VMA操作

    专题:Linux内存管理专题 关键词:VMA.vm_area_struct.查找/插入/合并VMA.红黑树. 用户进程可以拥有3GB大小的空间,远大于物理内存,那么这些用户进程的虚拟地址空间是如何管理 ...

  8. Linux内存管理 (8)malloc

    专题:Linux内存管理专题 关键词:malloc.brk.VMA.VM_LOCK.normal page.special page. 每章问答: malloc()函数是C函数库封装的一个核心函数,对 ...

  9. Linux内存管理 (9)mmap

    专题:Linux内存管理专题 关键词:文件映射.匿名映射.私有映射.共享映射 mmap/munmap是常用的一个系统调用,使用场景是:分配内存.读写大文件.连接动态库文件.多进程间共享内存. 更详细解 ...

随机推荐

  1. 还在用NuGet吗?大哥FuGet了解一下

    前言 你可能不知道是,NuGet已经发布10年了,从 Visual Studio 2010 第一次官方集成NuGet以来,这10年间有聚集了超过 14万 的包,这些包有超过 150万 的版本提供,大约 ...

  2. FragmentTabHostBottomDemo【FragmentTabHost + Fragment实现底部选项卡】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 使用FragmentTabHost实现底部选项卡效果. 备注:该Demo主要是演示FragmentTabHost的一些设置和部分功能 ...

  3. 目标检测 非极大值抑制(Non-Maximum Suppression,NMS)

    非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素,可以理解为局部最大搜索.也可以理解为只取置信度最高的一个识别结果. 举例:  如图所示,现在 ...

  4. 强化学习(十)Double DQN (DDQN)

    在强化学习(九)Deep Q-Learning进阶之Nature DQN中,我们讨论了Nature DQN的算法流程,它通过使用两个相同的神经网络,以解决数据样本和网络训练之前的相关性.但是还是有其他 ...

  5. Windows Server 2012 R2安装SqlServer 2016

    1.系统安装 微软操作系统 Windows Server 2012 R2 官方原版镜像 Windows Server 2012 R2 是由微软公司(Microsoft)设计开发的新一代的服务器专属操作 ...

  6. 【我们一起写框架】MVVM的WPF框架(二)—绑定

    MVVM的特点之一是实现数据同步,即,前台页面修改了数据,后台的数据会同步更新. 上一篇我们已经一起编写了框架的基础结构,并且实现了ViewModel反向控制Xaml窗体. 那么现在就要开始实现数据同 ...

  7. Docker最全教程——MongoDB容器化(十二)

    MongoDB容器化 MongoDB是一个免费的.开源的.跨平台分布式面向文档存储的数据库,由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和 ...

  8. Vb.net MakeLong MAKELPARAM 合并整数代码

    Function MAKELPARAM(wLow As UShort, wHigh As UShort) As UInteger Return wHigh * &H10000 + wLow E ...

  9. InnoSetup 脚本打包及管理员权限设置

    InnoSetup使用教程:InnoSetup打包安装 脚本详细 1. 定义变量 #define MyAppName "TranslationTool" #define MyApp ...

  10. App隐私条款

    欢迎光临本app,请您仔细阅读以下条款,如果您对本协议的任何条款表示异议,您可以选择不使用本app:进入本app则意味着您将同意遵守本协议下全部规定,并完全服从于app开发者的统一管理. 第一章 总则 ...