郝健: Linux内存管理学习笔记-第2节课【转】
本文转载自:https://blog.csdn.net/juS3Ve/article/details/80035753
摘要
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都不把内存还给内核。则从<do your RT-thing>之后,再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内存管理学习笔记-第2节课【转】的更多相关文章
- 郝健: Linux内存管理学习笔记-第1节课【转】
本文转载自:https://blog.csdn.net/juS3Ve/article/details/80035751 摘要 MMU与分页机制 内存区域(内存分ZONE) LinuxBuddy分配算法 ...
- Linux内存管理学习笔记 转
https://yq.aliyun.com/articles/11192?spm=0.0.0.0.hq1MsD 随着要维护的服务器增多,遇到的各种稀奇古怪的问题也会增多,要想彻底解决这些“小”问题往往 ...
- Linux内存管理学习笔记——内存寻址
最近开始想稍微深入一点地学习Linux内核,主要参考内容是<深入理解Linux内核>和<深入理解Linux内核架构>以及源码,经验有限,只能分析出有限的内容,看完这遍以后再更深 ...
- Linux内存管理学习笔记--物理内存分配
http://blog.chinaunix.net/uid-20321537-id-3466022.html
- C++内存管理学习笔记(7)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(5)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(6)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- Linux内存管理学习资料
下面是Linux内存管理学习的一些资料. 博客 mlock() and mlockall() system calls. All about Linux swap space 逆向映射的演进 Linu ...
- C++内存管理学习笔记(4)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
随机推荐
- from: Maven实战(九)——打包的技巧
from : http://www.infoq.com/cn/news/2011/06/xxb-maven-9-package 要点: 1. 打出可执行的jar包, 2. 自定义打包
- .NET创建宿主设计器--DesignHost、DesignSurface.
一个窗口在运行时,是这样的: 但是,在设计时,却远比这复杂的多,它需要一个设计器对象:它仅存在于设计时,并连接到运行时存在的对象. 宿主容器 我们可以看到每个窗体和按钮均有与之相关的设计器.这两个 ...
- Log4cplus入门
Log4cplus使用指南 1. Log4cplus简单介绍 log4cplus是C++编写的开源的日志系统,前身是java编写的log4j系统.受Apache Software License保护 ...
- 关于Blind XXE
关于Blind XXE 关于XXE,很早之前内部做过分享,个人觉得漏洞本身没太多的玩点,比较有意思主要在于:不同语言处理URI的多元化和不同XML解析器在解析XML的一些特性. 在科普Blind XX ...
- C 命令行参数
C 命令行参数 执行程序时,可以从命令行传值给 C 程序.这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了. 命令行参数是使用 ...
- 调用聚合数据新闻头条API
基于聚合数据新闻头条接口 支持阅读新闻类型包括: 各类社会.国内.国际.体育.娱乐.科技等资讯,更新周期5-30分钟. 新闻内容类型的多选,支持皮肤功能. 使用前需要有聚合数据账号,并实名制后通过 新 ...
- Material Design Get Started
使用Material Design设计应用: Take a look at the material design specification. Apply the material theme to ...
- JS批量获取参数构建JSON参数对象
在做系统的时候,往往查询条件是被严格指定的,大量的查询条件,一两个页面还可以通过dom去一个一个获取,再构建参数对象,请求后台接口. 这里给大家讲一个批量获取前端参数,构建参数对象. <form ...
- ZooKeeper 系列(一)—— ZooKeeper核心概念详解
一.Zookeeper简介 二.Zookeeper设计目标 三.核心概念 3.1 集群角色 3.2 会话 3.3 数据节点 3.4 节点 ...
- eclipse--windowBuilder
https://www.eclipse.org/windowbuilder/ https://www.eclipse.org/windowbuilder/download.php Documentat ...