
前言:
七月份的尾巴是狮子座~~
在这个尾巴里,老菊更完了七月最强新番《奴隶阿飞的励志人生》、在停更了两周以后,乔鲁诺也在《黄金之风》里揪着七月的尾巴成为了“秧歌star”。可反观我这一个月,《性能之巅》的学习一直没什么进展,有道是“日日待明日,万事成蹉跎”。

刚开始看“内存”部分,各种看不懂。。。那就先看“文件系统”吧,又是各种看不懂。。。干脆把磁盘部分一起看了,三个部分串起来应该能看懂了吧。看完以后把内存和文件系统的东西全部忘光了。。。真的不应该这么自信,挑战200多页。。。
在经历了“书读百遍,从入门到放弃”的体验以后。决定从最开始内存部分的疑问入手,结果运气爆棚的找到了思路。赶紧记录一下,激励一下自己。
正文:
回想一下的话,《性能之巅》在 cpu 部分的思路很简单:cpu 按照既定频率执行指令,分析 cpu 的使用情况其实就是对所有的指令进行分组,分到指令多的组,使用率高,可能需要优化。但是我们不可能统计所有的指令,所以内核使用抽样的方式,以时钟周期采样。将采样信息,按照进程和上下文分组,从而统计出了整个系统,乃至每个进程的 cpu 使用率。
同理,内存里边各种0101,如果也进行分组的话,就能统计出整个系统,乃至每个进程的内存使用率。而且仔细一想,内存还不用采样。按理说应该比cpu更简单才对。
反思整整200多页讲的东西,才忽然发现问题所在。不管是对于操作系统还是进程,cpu的分析只需要考虑“使用”和“不使用”两种状态。而分析内存的时候,对于已经使用的内存,书本更多的是在讲,这部分内存被用在什么地方了,所以搞出了[ buffer cache ][物理内存虚拟内存]等等,各种各样的概念。所以看不懂的真正原因是,不知道内存可以用在什么地方,也不知道内核如何统计每一部分的使用,所以更别提怎么分析内核的统计数据了。
之前说到的运气爆棚就是找到了一篇详细讲解内存相关统计信息的文章《/PROC/MEMINFO之谜》目前已经看了两遍,大概看懂了10%左右,但是初步的思路已经有了。
讲这10%之前,先感谢一下这位作者的其他几篇文章,把我之前看cpu部分的疑问都给解决了。
首先是我在《性能之巅》学习笔记之 cpuload 中错误的实验和错误的结论。可以参考理解 LINUX LOAD AVERAGE 的误区 这篇文章。之所以当时一大堆 sleep 的进程,cpuload 统计出来很高,是因为 linux 本身 cpuload 的统计就有问题。所以以后排查问题的时候,不要看这个字段就完了。
其次是写《性能之巅》学习笔记之 Dtrace 时候,其实并不清楚,动态追踪到底好在哪里。特别是后边学习火焰图的时候,发现很多统计信息 linux 的 perf 工具都能提供,而且非常方便。那干嘛还要费这么大劲安装这些难用的工具呢?DISK 100% BUSY,谁造成的?举了一个很具体的例子:简单说就是:“现成的工具不是万能的,但是动态跟踪是”
pidstat 和 iotop 也有不足之处,它们无法具体到某个硬盘设备,如果系统中有很多硬盘设备,都在忙,而我们只想看某一个特定的硬盘的I/O来自哪些进程,这两个命令就帮不上忙了。怎么办呢?可以用上万能工具SystemTap。
最后就是在《性能之巅》学习笔记之 linux 的 cpu 监控 时候留下的疑问。如果 cpu 统计是基于采样,那么 iowait% 是怎么统计的呢?理解 % IOWAIT (% WIO )这篇文章写的很清楚。
简单说,iowait统计的是idle的一部分。比如如果连续 1s 全部是 idle 。那么 idle %应该是 100%。如果总共采样100次,其中有1次有线程在等待 io ,那么最终统计结果: idle %=99%, iowait %=1% 。至于为什么这个统计信息不靠谱,就不再赘述了。
话说这个作者也是牛叉。感觉每篇文章都针对我之前的学习笔记~~
之所以前边说这么多,主要是本次内存只看懂了一点点。不够一篇文章的。下面就把这点心得整理一下吧:
要分析内存,首先想到的自然想到 vmstat 和 free。我最开始学习的时候,首先想到的就是 free 的 buffer 和 cache 到底是什么。具体某一个如果高了该怎么理解和解决。刚好作者有这篇帖子 FREE 命令显示的 BUFFERS 与 CACHED 的区别,简直是要什么来什么。
作者不仅介绍了strace free这样的骚操作,更是给出了整个内存分析学习的方向。那就是学习 /proc/meminfo 里边每一行的含义。《/PROC/MEMINFO之谜》这篇文章,我才看到 VmallocUsed 部分。因为看不懂,所以查了一下资料。然后找到了这篇帖子 Linux 内核 Vmalloc 区域大小的计算和这张图:

图片转自物理地址和虚拟地址的分布。
有了这两个。别的看不懂,/proc/meminfo 里边 Vmalloc 相关的总算能看懂了。按照图上的描述,内核空间总共 1 GB 内存,除去直接映射的 896MB ,剩下的 100多MB 就是 VmallocTotal 了。

可是仔细一想,不对啊,如果内核要申请 200MB 的动态内存怎么办?总不能失败吧。然后我就在自己的虚拟机里,cat /proc/meminfo ,结果打出了一个“海儿”大的结果:
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
妈耶,一个虚拟机,VmallocTotal 打印出来居然有 34TB ?!什么鬼,虚拟机总共物理内存也才 2G 而已。
很多讲 linux 内存的书籍,都会祭出这两张古老的图(一张物理内存,一张虚拟内存):


图片转自 Linux 物理地址和虚拟地址的关系
这两张图很容易就让人产生疑问,随便起个 java 进程,都能设置 几十GB 的内存,4GB 的虚拟内存怎么够用。包括之前在学习《Linux内核设计与实现(原书第3版)》的时候,书中提到的“高端内存( ZONE_HIGHMEM )”,当时也是看的云里雾里。
其实这些都是 32位 系统的东西,现在 64位 系统早就跟这不一样了。
之所以有“高端内存( ZONE_HIGHMEM )”,是因为 32位 系统,虚拟内存地址只有 4GB ,其中内核地址空间只有 1GB 。想要使用 1GB 的地址访问 4GB 的物理内存,只能“用了删,删了用”。但是 64位 不一样啊,64位 可以识别 16EB 的虚拟内存地址。目前电脑的内存肯定达不到 EB 级别,即使虚拟地址跟物理地址一一对应都够。所以根本不需要什么“高端内存( ZONE_HIGHMEM )。
那么,64位 系统的 linux 系统,虚拟内存怎么划分的呢?具体每一部分多大呢?我找到了这张图:

图片转自[内存管理] linux X86_64 处理器的内存布局图。其中,Vmalloc 大小是 32TB ,跟虚拟机里看到的接近。

这样就能明白 VmallocTotal 的含义了。然后就又有两个问题:
1.为什么虚拟内存只有 265TB ?不是 16EB 。
2.按照《/PROC/MEMINFO之谜》的描述,内核模块使用 Vmalloc 分配,为什么 VmallocUsed 是 0kb 呢?总不至于虚拟机一个内核模块都没加载吧。
第一个问题,参考为什么 64位 虚拟地址只能使用 48位 呢?
第二个问题,参考 /proc/meminfo says VmallocUsed is 0. So where are my kernel modules stored?
以上是今天学习的 5% 内容,下面是另外 5% :slab 。
之前学习《Linux内核设计与实现(原书第3版)》的时候,知道 slab 是用于分配内存的。这次搜索,发现很多文章都把 slab 和 buddy 放到一起讲。网上很多关于 buddy 算法 的介绍文章,大都提到这个算法能够减少内存碎片,但是基本上一堆文字,没有代码,没有图片。看完了基本上还是一头雾水。花了点时间,总算看明白了,我就想着,不如画个图描述一下,应该更直观。
首先说一下 buddy 和 slab 的关系,内核管理内存是以页(Page)为单位的。比如假设页大小是 4k ,如果程序想要使用 1k 的内存,直接分配 1页 就太浪费了。所以有了 slab ,用于分配和管理 小于1页 的内存。
对于 大于1页 的内存,自然是用 buddy 分配器来管理了。
首先简单描述一下,如果不实用buddy,内存是怎样泄露的。比如总共只有 16页 内存,分别标号为1~16,用白色方格表示。接下来执行下列操作:
分配2页(绿色)
分配1页(浅蓝色)
分配2页(黄色)
分配1页(浅灰色)
分配4页(橙色)
分配1页(深蓝色)
分配4页(深灰色)
释放1页(深蓝色)
分配2页(?)
如果不实用 buddy算法 ,结果大概如下图:


可以看到现在有两页内存可用,但是无法分配连续的两页了。也就是出现了碎片。
如果使用了 buddy 分配器 ,那么结果就是下边的样子:


可以看到,此时还是可以连续分配两页。
buddy 通过规定:“每次只能申请 2的n次方 页 ”这样的限制,实现两上图的效果。
具体代码这篇文章 伙伴系统算法 讲的很详细。这里节不赘述了。我刚开始看不懂代码。后来查了一下list_entry这个方法。看懂这个方法以后,这个代码就很简单了。
不过这次还是用“举例子”这中很 low 的方式勉强理解了这个算法。希望以后能从数学的角度,真正的理解这里边的原理。
结论:
一个月没写东西,攒的太多了。啰哩啰嗦写了一大堆。主要还是这200多页的问题。 学习果然是不能着急的。
之前有一次参加面试,被拒绝的原因是工作年限太少,我当时还特别 2 的跟面试官说,我很愿意学习,我可以每天加班加点,把工作经验补上。当时他跟我说:“有些东西,需要时间沉淀。不是加班加点能得到的”。现在大概理解了几分。
真正转化成自己的修养和学识,不是所谓的努力和运气,而是滚滚长江东逝水,青山依旧在,几度夕阳红~~
最后,让我们保持独立思考,不卑不亢。长成自己想要的样子!
(引用自 我非常喜欢的B站up主 ”独立菌儿“[->猛戳链接<-](https://space.bilibili.com/102984190/)的口头禅)