摘要

slab、/proc/slabinfo和slabtop

用户空间malloc/free、内核空间kmalloc/kfee与Buddy的关系

mallopt

vmalloc

Linux为应用程序分配内存的lazy行为

内存耗尽(OOM)、oom_score和oom_adj

Android进程生命周期与OOM

1.    slab、/proc/slabinfo和slabtop

Buddy的最小单位是页(4k),无论是内核还是用户程序都会申请一些更小粒度的内存,所以在Linux内核中类似于堆的内存申请都会基于二次分配器slab。

slab原理:比如申请8 byte内存,就从Buddy申请到4K,然后将4K分成很多个8 byte,每一个8 byte就叫做Slab的一个object。

slab机制的实现算法有slab,slub,slob。

Linux会针对一些小粒度内存的申请以及一些常规数据结构的内存申请做slab,可以cat /proc/slabinfo查看。

可以看出slab主要分为两类:一类是内核里常用的数据结构,如TCPv6,UDPv6等,由于内核经常要申请和释放这类数据结构,所以就针对这些数据结构做一个slab,然后再次申请这类结构体时就总是从这个slab里来申请一个object(使用kmem_cache_alloc()申请)。另一类是一些小粒度的内存申请,如slabinfo中的kmalloc-16,kmalloc-32等(使用kmalloc()申请)。

注意:slab是只针对内核空间的,与用户空间没有关系。

slabtop

slabtop displays  detailed  kernel slab  cache  information in real time.  It displays a listing of the top cachessorted by one of the listed sort criteria. It also displays a statistics header filled with slab layer information.

2. 用户空间malloc/free、内核空间kmalloc/kfee与Buddy的关系

所有的内存申请最终都来自Buddy,但malloc/free及kmalloc/kfree都不与Buddy一一对应,libc和slab都相当于二级分配器。

slab与Buddy的关系:

slab与Buddy都是内存分配器。

slab的内存来自Buddy

slab与Buddy在算法上级别对等。Buddy把内存条当作一个池子来管理,slab是把从Buddy拿到的内存当作一个池子来管理的。

3.    mallopt

mallopt(M_TRIM_THRESHOLD, -1UL); 控制libc把内存还给内核的门限。把门限设置为-1UL表示在任何情况下,libc都不把内存还给内核。则从之后,再malloc和free都是在之前申请的100MB内存池中进行,都不再与内核打交道,程序的实时性得以提高。这是一个在实时系统下的编程技巧。

4.    vmalloc

首先内存地址空间是包括物理内存+寄存器的,CPU在访问内存地址空间时都是经过virt->mmu->phys的过程。

图中内存空间中不同颜色的点都代表一页内存,无论是高端内存还是低端内存,都有可能被kmalloc,vmalloc和用户空间的malloc申请走(Buddy算法即是管理这一页是否被申请走的)。

malloc、vmalloc与kmalloc的唯一区别是malloc、vmalloc申请内存后需要修改页表,而kmalloc申请内存时由于已经做了开机线性映射,所以不需要修改页表。

寄存器是通过ioremap向vmalloc映射区去映射的,一旦调用ioremap,Linux就从vmalloc映射区找一个空闲的虚拟地址空间,然后去修改进程的页表,把这个虚拟地址往这个寄存器的物理地址去指。

vmalloc区域完成两个作用:

1)调用vmalloc从内核中申请内存并映射到vmalloc区

2)寄存器通过ioremap也映射到vmalloc区域

可以通过/proc/vmallocinfo文件查看

附注:

MMU通过虚拟地址察物理地址,不同的虚拟地址是可以对应一个相同的物理地址的:

理解页表最简单的方法(先只考虑一级页表),可以把页表想象成一个一维数组(a[1M],1M个成员是因为32位宽的地址,低12位作页内偏移,高20位对应第几页),CPU访问虚拟地址时,MMU用高20位作为数组的下标去取物理地址,比如假设成取a[i]成员,则a[i]中存物理地址,RWX权限和user/kernel权限。所以,两个不同的虚拟地址a[i]和a[j]中的内容(物理地址)相同是完全可能的。

5.    Linux内核为应用程序分配内存的lazy行为

如,在用户空间成功申请100M内存时并没有真的申请成功,只有100M内存中的任意一页被写的时候才真的成功。

用户空间malloc成功申请100M内存时,Linux内核将这100M内存中的每一个4K都以只读的形式映射到一个全部清零的页面(这其实不太符合堆的定义,堆一般是可读可写的),当任意一个4K被写的时候即会发生page fault,Linux内核收到缺页中断后就可以从硬件寄存器中读取到缺页中断的地址和发生原因。之后Linux内核根据缺页中断报告的虚拟地址和原因分析出是用户程序在写malloc的合法区域,此时Linux内核会从内存中新申请一页内存,执行copy on write,把全部清零的页面重新拷贝给新申请的页面,然后把进程的页表项的虚拟地址指向一个新的物理地址。同时,页表中这一页地址的权限也修改为R+W的。注意以页单位发生page fault。

VSS - Virtual Set Size

RSS - Resident Set Size

图中第一步,堆初始为8K已写8K,所以RSS为8K;第二步调用brk扩展堆为16K,此时VSS变为16K,但RSS仍然是8K;第三步,写堆的第三页发生page fault;第四步,写时拷贝,RSS变为12K。以此类推,写第四页成功后RSS才会变为16K。

注:Lazy机制可以理解为“欺骗应用程序”。但在内核空间调用kmalloc是不欺骗的,要么分配成功,要么分配失败。

6.    内存耗尽(OOM)、oom_score和oom_adj

Linux在运行时会对每一个进程进行一个Out of Memory的打分(基于进程所耗费内存的大小,耗费越多分数越高)。可以通过/proc/pid/oom_score文件查看分数。一旦内存耗尽,Linux内核会kill掉当前oom_score分值最高的进程。

例1:编译图上程序,swapoff -a将交换分区关闭,并且配置overcommit_memory为1(允许应用程序申请很大的内存,而内核不再去评估系统中当前还有多少内存可用。):sudo sh -c ‘echo 1 > /proc/sys/vm/overcommit_memory’(echo不会启动一个新的进程,所以加sh -c,在新的shell中执行,这样才能使sudo有效),然后运行。可以发现在运行一段时间后此程序被杀死,dmesg查看:

Out of memory:score分数848被杀死。

另外,OOM打分还会看一些其他的因子,如下图所示:

例2:启动另一个进程firefox,同样关闭swap分区并配置overcommit_memory为1,然后将firefox的oom_score调到最高,运行例1中的a.out观察哪个进程先被杀死。

如上图所示,写入到oom_adj的数值越大,导致oom_score的打分越高,越容易被杀死,此时写入不需要root权限,但想使其打分值变小则需要root权限,这也是符合现实意义的。

运行例1中的a.out,可以发现由于firefox的oom_score更高,所以先被杀死,但一段时间过后再次发生Out of memory,a.out也被杀死。

7.    Android进程生命周期与OOM

Android在程序退出时候,并不杀死进程,而是等OOM发生后再杀死。Android根据不同的进程类型设置不同的oom_adj。这样做的目的就是为了最大程度上的提高用户体验。

LINUX应用修改硬件寄存器l,郝健: Linux内存管理学习笔记-第2节课【转】相关推荐

  1. 郝健: Linux内存管理学习笔记-第6节课

    前序文章: 郝健: Linux内存管理学习笔记-第1节课 郝健: Linux内存管理学习笔记-第2节课 郝健: Linux内存管理学习笔记-第3节课 郝健: Linux内存管理学习笔记-第4节课 郝健 ...

  2. 郝健: Linux内存管理学习笔记-第5节课

    前序文章: 郝健: Linux内存管理学习笔记-第1节课 郝健: Linux内存管理学习笔记-第2节课 郝健: Linux内存管理学习笔记-第3节课 郝健: Linux内存管理学习笔记-第4节课 摘要 ...

  3. 郝健: Linux内存管理学习笔记-第4节课

    前序文章: 郝健: Linux内存管理学习笔记-第1节课 郝健: Linux内存管理学习笔记-第2节课 郝健: Linux内存管理学习笔记-第3节课 摘要 page cache free命令的详细解释 ...

  4. 郝健: Linux内存管理学习笔记-第1节课【转】

    本文转载自:https://blog.csdn.net/juS3Ve/article/details/80035751 摘要 MMU与分页机制 内存区域(内存分ZONE) LinuxBuddy分配算法 ...

  5. 郝健: Linux内存管理学习笔记-第3节课

    摘要 进程的虚拟地址空间VMA(Virtual Memory Area) Pagefault的几种可能性.VMA的作用.major缺页和minor缺页 进程内存消耗的4个概念:vss.rss.pss和 ...

  6. 郝健: Linux内存管理学习笔记-第2节课

    摘要 slab./proc/slabinfo和slabtop 用户空间malloc/free.内核空间kmalloc/kfee与Buddy的关系 mallopt vmalloc Linux为应用程序分 ...

  7. 郝健: Linux内存管理学习笔记-第2节课【转】

    本文转载自:https://blog.csdn.net/juS3Ve/article/details/80035753 摘要 slab./proc/slabinfo和slabtop 用户空间mallo ...

  8. 郝健: Linux内存管理学习笔记-第1节课

    摘要 MMU与分页机制 内存区域(内存分ZONE) LinuxBuddy分配算法 CMA(连续内存分配器) 0.    课前阅读 宋宝华:CPU是如何访问到内存的?--MMU最基本原理 http:// ...

  9. Linux命令行与shell脚本编程大全第三版 学习笔记

    Linux自己的文件资料: /usr/share/doc (在你的Linux系统中) https://www.osyunwei.com/archives/290.html 0. 注意Linux中一切皆 ...

最新文章

  1. IIS配置相关问题:Framework 4.5 在IIS 7.5中运行
  2. [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)
  3. CSS3给网页穿上美丽的外衣
  4. 报应!GitHub上线围剿Python计划,已有4万人跟进,你呢?
  5. Android演示Stack(课下作业)
  6. 手游:cocos2d-x3.0 移植 wp8 开发 各种 “蛋疼”问题的汇总
  7. 2020千月最新影视源码 对接苹果影视app小白零基础搭建视频教学可赚钱影视APP
  8. 用cmd命令下载百度云的资源
  9. STM8开发环境搭建(STVD + COSMIC)
  10. spyder缩进快捷键
  11. 如何更好地吸收维生素矿物质?
  12. 【2019暑假】市中小学生游泳比赛-酱油记By Chavapa
  13. 最新多目标跟踪算法综述-2020年08月23日
  14. linux驱动原载-- touch pannel驱动
  15. 【java】java intellij idea 破解
  16. 大数据平台的作用有什么
  17. 无法启动程序 系统找不到指定的文件
  18. js判断数据类型常用的四种方法
  19. PCIe 5.0 spec学习4.1----PCI-PM(part1)
  20. PLC上位机程序开发

热门文章

  1. 机器学习:基于关联规则的多标签分类器
  2. Ril分析五——ril学习总结
  3. linux从源码编译软件,linux软件包管理——源码包编译安装
  4. python中给出一个不超过10的正整数n_求计算机大佬解答python题
  5. python如何实例化类_Python如何根据类名实例化类
  6. go 类型 value 不支持索引_10分钟掌握PostgreSQL 5种索引的应用场景
  7. maven编译java1.8项目_maven正在用java 1.7编译代码,但我想用1.8编译它
  8. 计算机话筒接口,电脑麦克风插口是哪个哪位知道?
  9. python划分代码_多分类评价指标python代码
  10. php 动态链接,LevelDB(动态链接) + PHP扩展 安装