目录
4.4 假如程序A申请1GB的内存,这申请的过程中,内存演变的过程
4.6 kswapd字段的含义,且他的活动频繁会对内存和CPU有哪些影响
4.10 在内存置换的过程中,used 一直未没有发生变化的原因
一、早期的内存使用与内存管理技术演变
在早期的计算机中,程序是直接运行在物理内存上的。换句话说,就是程序在运行的过程中访问的都是物理地址。如果这个系统只运行一个程序,那么只要这个程序所需的内存不要超过该机器的物理内存就不会出现问题,我们也就不需要考虑内存管理这个麻烦事了,反正就你一个程序,就这么点内存,吃不吃得饱那是你的事情了。然而现在的系统都是支持多任务,多进程的,这样CPU以及其他硬件的利用率会更高,这个时候我们就要考虑到将系统内有限的物理内存如果及时有效的分配给多个程序了,这个事情本身我们就称之为内存管理。
这种内存管理方式存在几个比较明显的问题:
- 进程地址空间不能隔离
由于程序直接访问的是物理内存,这个时候程序所使用的内存空间不是隔离的。举个栗子,就像程序A的地址空间是0-10M这个范围,但是如果A中有一段代码是操作10M-128M这段地址空内的数据,那么程序B和程序C就很可能会崩溃(每个程序都可以系统的整个地址空间)这样很多恶意程序或者木马程序可以轻而易举的破坏其他的程序,系统的安全性也就得不到保障了,这对用户来说也是不能容忍的。
- 内存使用的效率低
如上面提到的,如果我们要像让程序A、B、C同时运行,那么唯一的方法就是使用虚拟内存技术将一些程序暂时不用的数据写到磁盘上,在需要的时候再从磁盘读回内存。这里程序C要运行,将A交换到磁盘上去显然是不行的,因为程序时需要连续的地址空间的,程序C需要20M的内存,而A只有10M的空间,所以需要将程序B交换到磁盘上去,而B足足有100M,可以看到为了运行程序C我们需要将100M的数据从内存写到磁盘,然后在程序B需要运行的时候再从磁盘读到内存,我们知道IO操作比较耗时,所以这个过程效率将会十分低下。
- 程序运行的地址不能确定
程序每次需要运行时,都需要在内存中非配一块足够大的空闲区域,而问题是这个空闲的位置是不能确定的,这会带来一些重定位的问题,重定位的问题确定就是程序中引用变量和函数的地址。
内存管理无非就是想办法解决上面这三个问题,如何使进程的地址空间隔离? 如何提高内存的使用效率? 如何解决程序运行时的重定位问题?
引用一句计算机界的 一句名言“计算机系统里的任何问题都可以靠引入一个中间层来解决。”
现在的内存管理方法就是在程序和物理内存之间引入虚拟内存这个概念。虚拟内存位于程序和物理内存之间,程序只能看到虚拟内存,再也不能直接访问物理内存。每个程序都有自己独立的进程地址空间,这个就可以做到进程的隔离。这里的进程地址空间指的是虚拟地址。
既然我们在程序和物理地址空间之间增加了虚拟地址,那么就要解决怎么从虚拟地址映射到物理地址,因为程序最终肯定是运行在物理内存中的,主要由分段和分页两种技术。
分段:这种方法是人们最开始使用的一种方法,基本思路是将程序所需要的内存地址空间大小的虚拟空间映射到某个物理地址空间。
这种分段的机制解决了上文提到的三个问题中的进程地址空间隔离和程序地址重定位的问题。这种内存映射机制仍然是以程序为单位,当内存不足时仍然需要将整个程序交换到磁盘,这样内存使用的效率仍然很低。怎么才算高呢?
根据程序的局部性运行原理,一个程序在运行的过程当中,在某个时间段内,只有一小部分数据会被经常用到,所以我们需要更加小粒度的内存分割和映射方法。此时是否会想到linux中的Buddy 算法和slab 内存分配机制呢。将虚拟地址转换为物理地址的分页机制应运而生。
分页机制:把内存地址空间分为若干个很小的固定大小的页,每一页的大小有内存决定,就像linux中ext文件系统将磁盘分成若干个Block一样,这样做分别是为了提高内存和磁盘的利用率。内存中的分页机制跟ext文件系统中的磁盘分割机制非常相似。
linux 中一般页的大小是4KB,我们把进程的地址空间按页分割,把常用的数据和代码页装载到内存中,不常用的代码和数据保存在磁盘中,如下图:
上图分页机制的内容,讲内存映射页的关系的时候,再进行分析与详解。
二、free命令详解
2.1 基本名词解析
total :物理内存的实际总量
used:总计分配给缓存(buffer+cache)的使用的数量,但是其中部分可能并未实际使用(这里不是实际使用了的内存)
free:未被分配的内存(真正的空闲,未被任何程序占用)
shared : 多个进程共享的内存总额
buffers:磁盘缓存(buffer cache)的大小(可提高I/O调用的性能),系统分配的,但是未被使用的buffer剩余量
cached: 磁盘缓存(page cache)的大小(可提高I/O调用的性能),系统分配的,但是未被使用的cache剩余量。
-buffers/cache:表示已被我们程序使用的内存数,计算方法:used-buffers-cached(注意:这里才是内存的实际使用量)
+buffers/cache:表示还可被我们使用的内存数,计算方法:free+buffers+cached
swap: 交换分区总量,使用量,剩余量
2.2 buffer 与 cache 的区别?
- cache 高速缓存
- 文件系统的缓冲(page cache)
- buffer 缓冲区
- 块设备的读写缓冲区(buffer cache) ,buffer目录和下面的节点
- 都是为了解决读写慢,提高IO效率
- 对于缓存服务器来说,内存的使用就包含buffers和used
cache多好还是少一点好?
- 需要考虑实际的场景和使用的频次,还需要考虑命中率的问题
- 热点资源cache 住,提高效率,冷数据没必要
2.3 内存计算公式
内存公式的计算,需要判断buffer 和 cache 是否可以清理
- used包含了buffer和cache,才有了+buffer/cache和-buffer/cache
- total.used(系统使用内存) = -/+buffer.cache.used(实际使用内存排除buffer,cache) +buffer +cache
- mem.used = +-buffer/cache.used +buffer +cache
- mem.free = +-buffer/cache.free - buffer - cache
- mem.total = men.used +mem.free
- mem.total = (+- buffer/cache.used) + (+-buffer/cache/free)
- swap.total =swap.used + swap.free
2.4 物理内存使用公式
注:根据服务器的性质来考虑内存使用公式
2.4.1 只有物理内存,无swap
缓存服务器:men.used / mem.total
非缓存服务器:(-/+buffers/cache).used / mem.total
非缓存服务器因为 buffer 和 cache 可以释放,所以mem.used 需要减去 buffer 和cache
2.4.2 有物理内存,有swap
缓存服务器:mem.used + swap.used 【已使用内存】
(mem.used + swap.used) / (mem.total + swap.total) 【内存使用率】
非缓存服务器:mem.used - buffers/cache + swap.used 【buffer 和cache 可被释放】
(mem.used- buffers/cache +swap.used) / (mem.total + swap.total) 【内存使用率】
案例1:在压测的过程中(vmstat 1 5 进行内存监控),程序A先申请100M内存(free -s 1),free 和buffer、cache 再同时减少
案例2:在压测的过程中(vmstat 1 5 进行内存监控),程序B先申请100M内存,free 减少了,但buffer、cache 没有变化,这两个案例分别说明了什么?
- 案例1,free 当前内存不够了,程序A已经在使用buffer和cache的内存
- 案例2,free 当前内存足够
结论:程序申请内存,先使用free ,free不足的时候,在释放 buffer 和 cache ,从buffer 和 cache 去消耗内存
2.4.3 如何手动释放buffer 和cache 内存
释放buffer 和cache内存操作前,我们先温习下他们的作用,作用就是为了提高系统的IO能力
- cat /proc/sys/vm/drop_caches
- echo 3 > /proc/sys/vm/drop_caches 【0. 不释放 1. 释放页缓存 2. 释放dentries和inodes 3. 释放所有缓存】
- sync ---内存的数据同步磁盘
释放后的内存,进入到了 free, used 相应的减少,如果没有进行sync 磁盘同步,那么释放掉的buffer和cache 空间就丢掉了,需要重启服务器
通常情况下,我们不应该为了free的空间而随意的去清理buffer和cache,治标不治本。当发生内存不足、应用获取不到可用内存、OOM错误等问题时,还是更应该去分析应用方面的东西。当前在无法避免的情况下,我们是可以临时清空,但问题终究需要彻底解决。
2.5 内存阈值定义
既然swap的作用是置换,那在分析内存阀值的时候,需要把swap 给算进去
- 根据压测情况,系统资源情况,这样的实际情况来决定,没有固定的百分比
- 内存的阈值定义,并不是拍脑袋说50% 70% 90%,而是要根据实际的业务场景而定
swap total 数据要小点,当swap 太大的时候,此时内存还没告警, io cpu 已经告警,使用数建议不超过4G,不然频繁置换,影响IO问题
- 在当前时间节点,资源以不在是多么奢侈的事情,当服务器资源都已经在128G以上时,设置swap虚拟内存空间已经没有多大必要(很多企业的服务器已不再设置swap),当系统内存遇到瓶颈时,大量的内存置换,也会造成其他系统异常(如cpu、IO)。一定要设置,swap 一般是物理内存的2倍,但不建议超过4G。
2.6 swap 太大或太小会遇到的几个问题
2.6.1 swap 太大,套用公式是否合理
不合理。swap太大,阀值公式是需要改变的,不然会导致内存不告警,IO已经告警。如果系统已经在大量使用swap空间,其实已经告诉我们,内存不足了。
有如下场景,非缓存服务器(4核8G物理内存),压测时最高点3G,压测前后的mem.free是300M左右,压测过程前中后,(mem.free+buffer+cache)/total.mem基本上都是占70%,且swap没有被使用,结合这些信息,服务器的内存使用上是否有问题?
- free 很少,才300M。buffer和cache 很高
- 8000 * 70% -300 = 5300(说明都被buffer 和 cache使用了)
说明大部分都被buffer cache 住了,基于非缓存服务器,可以认为内存是没有问题的。
2.6.2 swap 太小,套用公式是否合理
内存公式不需要变,物理内存足够大时,可以忽略swap。
三、内存利用率瓶颈怎么去分析
1. free 和swap 就相当于你的现金流和银行的贷款。到要一定得去消费的时候,比如买房子,你可能是贷款(用free 首付 + swap 贷款) 或者是全款(全部 free) ,甚至可能是全部借款(消费贷款 + 银行贷款)。所以衡量你财务是否有问题就有这几个方面,贷款了多少,剩余的现金流多少
2. 一般我们是选择第二个来分析内存使用率的((mem.used + swap.used)/(mem.total + swap.total)),但是别忘记了,有时候 buffer 和cache 也是可以释放的,就想衡量你财务时候,股票,房产,汽车也是可以变现的
3. free很小,但是swap 没用的话,就好比你没借过钱,现金流比较少,一般是可以说明没有用到虚拟内存,这时候套用公式的话,一般是会说明内存没问题的
4. in、cs(vmstat命令中的指标) 多的时候,反应的是类似进程切换频率,调用内核态的较多,他们俩个高不一定推出内核sy 高,有可能是进程状态切换频繁,有可能是CPU不足,这个需要具体情况具体分析vmstat 1 5(进程状态:D --->堵塞 R --->运行)
有时候会出现一种情况,物理内存够用,但还是使用到了swap。这是因为系统存在内存被进程锁死的情况,如果进程被锁死就不能被置换,这个时候就需要用到swap 虚拟内存
四、vmstat 内存分析命令详解
4.1 swap字段(so 与 bo)
- 当userd内存不够用的时候,cache、bufree、free 的内存会给到userd 使用
- used 砍掉一部分内存数据块(inactive如100M)给free,砍掉一部分内存给swap,这就是so
- 把inactive的内存释放掉,把数据写入swap。一次 so 触发一次 bo 。反应一种速率,也就是设备块每秒
总结:内存不足,从used里面分一块,从used(置换inactive)里面分一块到swap,so的值会增加
si:从swap置换回物理内存 so:从物理内存置换到swap空间
当so的值在逐渐增大,说明used 的部分空间在写到swap空间,这是个信号,表示程序在频繁的使用swap空间,物理内存不足。
4.1.1 inactive 与 active 的区别?
- vmstat -a 列出的是 active 和inact的内存,一般在LRU的算法会优先置换inactive的,等到没有inactive的才会考虑用active 和cache
- vmstat -a 会展示 inactive内存有多少,active内存有多少
4.1.2 so有数据就说明内存不足吗?
不一定,如果程序刚好需要使用内存,又刚好没有,就需要置换到swap。但如果这个时候有一个占用内存的进程释放内存,这个时候就不对,内存并没有问题。性能诊断分析永远都是具体问题综合分析的结果。
如果是so值增高,swap使用率一直在增长,且free 已经很少。这种情况才能直接推断出内存不足,不然只能推出物理内存不足,因为虚拟内存也是内存的一部分。
4.2 IO 字段(bi 与 bo)
只有bi有值,而bo si so 均没有值,通过这个栗子来理解IO字段知识点。
- bi反应的磁盘写,bo 反应的是磁盘的读,所以有读不一定有写
- bi 块收到一个块设备(块/ s) 【512个字节是一个设备块/s】反应的是磁盘的写
- bo 体现的是设备块(扇区)每秒:块送到一个块设备(块/ s),反应的是磁盘的读
- swap的si so其实是在swap 分区上的,这个是在硬盘特别的分区,所以si、so 也会触发一次bo、bi
si有数据即so必有数据,so有数据即bo必然也有数据,正向推断可以的,但不能反向推。原因是,swap的读写仅仅是磁盘读写的一部分,如果内存足够大,根本就不需要swap,那么si,so 也就不会有数据。
场景1:纯硬盘写(无swap置换),与so、si 无关,只与 bi bo 有关。这种情况下,bo bi 很忙,说明IO有问题,会体现在CPU上,反映在cpu的%wa 字段的数据上
场景2:纯硬盘写(有swap置换),此时内存不足的情况下,需要去进行swap置换,与so、si 有关,也与 bi bo 有关。
场景3:如果free 比较少,swap 用的也比较少,si so 没有数据,内存怎么分析?
- 通过vmstat 来分析,套缓存与非缓存服务器资源利用率的公式
- swap 用的少,si so 没有数据,初步判定内存没问题
- 最终分析思路,还是要加buffer 和cache的使用情况而定
场景4:%wa 有数值,bi和bo也有数值,是否就能推导IO有问题?
不一定,512个字节是一个设备块,从单一的数据(如%wa 99)来分析,并不算高 (512byte/s)
不能以一次99来分析IO有问题,还需要结合整理来进行分析。
场景5:如下图,swap 增加, so也增加,是否说明内存不足?
- 不能直接说明内存不足,还需要考虑buffer 和cache的大小(如果buffer 和 cache 很大,不能说明内存不足)
- 如果是free + buffer +cache 很小,swap 增加,说明内存不足
结论:结合上图,so值很高,swap 使用率一直在增高,且free已经很少,说明物理内存不足
场景6:参考上图,system 中的 in cs 多少算高,一般 in cs 高的时候是不是cpu 也会增高?
- in 反映的是中断(包括:硬件中断,软件中断)
- cs 反映的是上下文切换 (比如,一个 tomcat进程,进程时间片用完了,就会触发上下文切换,把这个程序的数据段信息记录下来,等待下一次的被唤醒及调用)
cs in 反应的是对内核调用的一些情况,通常进程比较多的时候,时间片轮转调度比较频繁,in cs 数值会很大
in cs 多的时候,反应的是类似进程切换频繁,调用内核态的较多,他们两个高不一定推出内核sy 高,有可能只是进程状态切换频繁,有可能是cpu不足,需要具体情况具体分析
反之,CPU不足时,为什么cs 值就会变大?
- 负载大,进程切换频繁,会反映在cs 上面
- 10个进程,要去抢占cpu,然后cpu不足,各进程相互抢占cpu,导致频繁的上下文切换(cs高)
4.3 vmstat其他的几个指标含义
- system
- in 每秒的中断数,包括时钟中断
- cs 每秒的环境(上下文)切换次数
- cpu
- us:用户态使用cpu时间
- sy:系统态使用cpu时间
- id:闲置时间
- wa:IO时间等待
- st:虚拟机的资源正被另一台抢占
4.4 假如程序A申请1GB的内存,这申请的过程中,内存演变的过程
- 先使用物理内存,物理内存不足(free)
- free 不够,开始吃 buff 和 cache
- buff 和cache也不足,才开始吃swap 虚拟内存
- so开始从物理内存置换内存到swap
- free 值很小,而 swpd 值逐渐增大,开始消耗swap内存
4.5 通过vmstat 命令分析资源的使用情况
通过上图的资源情况,分析后存在如下问题:
- CPU列显示,id 空闲都为0,说明系统已经没有空闲的cpu
- id 为零,而 wa 达到了70以上,IO肯定是主要问题(CPU问题是IO影响的)
- swap 内存已经是free的几倍了,物理内存不足,系统还在不停的在进行so(置换swap内存)
- swap 影响了IO, 物理内存不足
- so 和si 都会反映在 bo 和 bi 上面
- 因为swap是从硬盘划分出去的分区,所以 swap分的太高,会对IO造成影响
- 每次so 都会反映在bo上面(一次so 触发一次 bo)
- 每次si 也会反映在bi 上面
- so 和 si 高,可以推算 bo 和 bi 一定高。但bo 和 bi 高,是不能推算so 和 si 一定高(前面已讲述原因)
总结:
- 物理内存不足 ----> 影响到swap ----> 影响到IO
- swap高,会不停的进行IO读写 ----> IO读写高,导致大量的wa等待 --->最终导致CPU高
- 不管网络问题、IO网络、cpu问题、内存问题,都可以先找相应的进程,归根到底,找进程
优化:
- 考虑加内存,做内存优化,降低这么多的swap置换,才能解决问题
- 加深理解,当物理内存512MB,分配8GB的swap是极不合理的做法,系统会频繁的读swap,swap内存置换使用si、so,最终导致wa高,cpu不足
4.6 kswapd字段的含义,且他的活动频繁会对内存和CPU有哪些影响
- kswapd是一个内核线程,他就是用来处理页面的交换,他可以在内存不足的时,将一些进程的页面置换到swap 空间之中(so si)
- 一般来说,他如果活动频繁,意味着系统在进行大量的so si,一般他的cpu会增长的有点厉害
- swap 内存置换的时候,kswapd就开始频繁活动
栗子:
ps aux | grep swap
top -p 30(top 命令进入 swap 进程查看信息)
本想通过脚本模拟,申请1000MB内存的场景,看各资源的表现,但本机没有设置swap,直接给结论吧!!
- CPU会增长上去,swap.used 在不停的增加,等置换完,则会退出
- so 比较多的时候,会反映在kswapd占用了cpu
想必大家都会有个疑问,设备的物理内存是有限的,当buffer, cache ,free出现内存不足时,为什么free 的值不会直接变成0呢?
- 进程锁定的内存不会释放,不会置换到swap
- 内核参数里有限定最小的 free, buffer, cache值
当内存发生不足时,首先会出现IO 瓶颈,然后出现wa 阻塞,最终导致cpu不足。
常见问题:当内存不够用的时候,系统可能会kill 使用内存最大的进程或者直接重启系统。
4.7 内存部分够用的情况下,swap的变化情况
4.7.1图 - 程序申请1GB内存监控图
结合上图(4.7.1图),分析内存在变化情况:
- 10:39:54,开始消耗free 的内存空间
- 10:39:55 ~ 10:39:56,开始消耗buffer 和 cache 的空间
- 10:39:57,开始消耗swap 的空间,并伴随so值的上升
结论:先消耗free,在消耗buffer 和 cache,最后在消耗swap,置换内存
swap 置换的过程:
- 通过used里的inactive内存释放,内存进入到了free buffer 和cache,所以在置换的过程中, free buffer和cache还可能会略微的增长
- swap发现 free buffer和cache有数据,在进行抢占,再进行swap置换。是一个循环置换,抢占的过程
如上图(4.7.1图),10:39:56 ~ 10:40:13秒时间段,id% = 0,其原因是:
- 实时采集top 的实时监控数据 【 top -d 1 >>top.txt #每秒钟采集一次top数据】
- 根据39秒时间段,查找对应top的监控数据
- 发现kswapd0占大部分cpu,在频繁的进行swap置换
- kswapd0线程进行内存置换和申请1000M内存的文件占用了大部分cpu,导致cpu不足
- kswapd 进程占CPU比较高一般都在进行so si ,系统应该是在进行swap置换(kswapd占cpu的10%以上,系统有比较多的置换)
怎么从top.log 文件中,如何定位cpu的%id =0 的top快照?
- grep Cpu top.txt -n # -n显示对应的行数,如 2211行 id%数据为零
- vim top.txt +2211 #直接定位到2211行数据
- 找出当前快照下,占cpu 的进程,对进程进行分析
4.7 常用的几个查询命令
- 查询某列的值,且包含某些值得语句
grep 'Cpu' top.txt | awk '{print $8,$0}' | grep ^99.8 # 显示该列包含99.8数值的行信息
- 查询关键字前后几行的数据信息
grep Mem -A 5 -B 5 top.txt # -A 向后5行 -B 向前5行 -C 向前后5行
- 统计第七列的数据
cat top.log | awk '{print $7}' | sort | uniq -c
- 显示第七列,状态为D的数据
cat top.log | awk '{print $7,$0}' | grep ^D
- 显示Mem 前后5行的数据
grep Mem -A 1 -B 5 top.log
- 显示进程状态为D的数据
grep D top.log
4.8 几个监控数据采集的命令
- while true; do date; free -m; echo; sleep 1; done # 每秒采集一次free的数据
- top -b -d 1 > top.log # 每秒采集一次top的数据
- vmstat 1 -t # 每秒采集一次内存监控的数据
4.9 文件对比(top 实时监控数据对比)
- top -b -n 1 >top1.log
- top -b -n 2 >top2.log
- vimdiff top1.log top2.log
4.10 在内存置换的过程中,used 一直未没有发生变化的原因
4.7.2图 - 程序申请1GB内存,内存置换过程中,free的情况图
从上图可看到,buffer 和 cache 一直有释放,而used内存没发生变化。原因是:一有物理内存就会被使用掉,永远保证内核限定最低内存的保留值(used/buffer/cache)
已经完成11GB的内存置换,系统为什么还会向swap里面用内存,是否合理(free 还在继续增加)?
合理,系统还有哪些程序,系统认为是inactive的内存,系统还继续swap置换
操作系统,内核有一个设置,物理内存不足的时候,尽可能的使用swap
根据上面的案例分析,可以得出以下几个结论:
- 有物理内存的 free buffer cache 优先使用
- 当物理内存不够,开始使用swap,这时候ram.used inactive 内存会置换到swap里面,释放掉的会进buffer cache free 供系统调用
- 进行置换的时候,kswapd 会占用一定的cpu,可以得出结论kswapd cpu 有数据,证明在置换
- swap 与 io 的关系 si 和 bi 一次, so 和 bo 一次 【不可反向推导】
- 当程序申请完成以后,系统还是会进行swap置换(将inactive物理内存置换到swap)
4.11 如何查看inactive 内存
cat /proc/meminfo # 里面会标注inactive内存有多少,系统实时都在计算是否要做置换
五、sar 命令详解
sar [options] [-A] [-o file] t [n]
其中:
t为采样间隔,n为采样次数,默认值是1;
-o file表示将命令结果以二进制格式存放在文件中,file 是文件名。
options 为命令行选项,sar命令常用选项如下:
-A:所有报告的总和
-u:输出CPU使用情况的统计信息
-v:输出inode、文件和其他内核表的统计信息
-d:输出每一个块设备的活动信息
-r:输出内存和交换空间的统计信息
-b:显示I/O和传送速率的统计信息
-a:文件读写情况
-c:输出进程统计信息,每秒创建的进程数
-R:输出内存页面的统计信息
-y:终端设备活动情况
-w:输出系统交换活动信息
- 系统使用的物理内存为18.11KB
- 程序使用的内存应减去buffer 和cache
- %commit 可以评估系统当前需要提交的进程内存数
sar 与vmstat 都是监控内存的工具,记住其中一个即可,我常用的是vmstat工具。
六、内存管理理论
6.1 内存映射页的关系
延续第一章节的内容,分页机制,通过下图理解内存映射页之间的关系
VIRT 对应的是虚拟地址空间,RES 对应的是物理内存,swap 对应的是磁盘DP0、1
si so 如果从理论出发的话,其实就是把物理内存与虚拟地址空间的映射关系,在磁盘中进行映射
swap(虚拟的内存块)其实是把磁盘的一个页跟虚拟地址页进行映射
- 最早的逻辑,是直接在物理内存进行申请
- 但是因为后面需要考虑一些共享的内存(可能两个程序共用同一个程序段或数据段的情况),物理内存会和虚拟地址有一个映射的关系
- 虚拟地址空间上面的每个页会去跟我们的内存地址页映射上,进行一 一 对应
- VART 其实是指虚拟地址空间(top)
6.2 常用的页面置换算法
先进先出法:(置换次数比较多)
最佳置换法(OPT):选择将来不在使用或在最远的将来才被访问的页调换出来(不便于实现)
最近最少使用置换法(LRU):当需要置换一页时,选择在最近一段时间里最久没有使用过的页面予以淘汰
最近未使用置换法(NUR):与LRU算法的近似方法,选择在最近一段时间里未被访问过的页面予以淘汰
内核把物理页作为内存管理的基本单位。尽管处理器的最小可寻址单位通常为字(甚至字节),但是,内存管理单元(MMU,管理内存并把虚拟地址转换为物理地址的硬件)通常以页为单位进行处理。正因为如此,MMU以页(page)大小为单位来管理系统中的页表(这也是页表名的来由)。从虚拟内存的角度来看,页就是最小单位。
由于硬件的限制,内核并不能对所有的页一视同仁。有些页位于内存中特定的物理地址上,所以不能将其用于一些特定的任务。由于存在这种限制,所以内核把页划分为不同的区(zone)。内核使用区对具有相似特性的页进行分组。linux 必须处理如下两种由于硬件存在缺陷而引起的内存寻址问题:
- 一些硬件只能用某些特定的内存地址来执行DMA(直接内存访问)
- 一些体系结构其内存的物理寻址范围比虚拟寻址范围大得多。这样就有一些内存不能永久地映射到内核空间上
因为存在这些制约条件,linux使用了三种区:
- ZONE_DMA:这个区包含的页能用来执行DMA操作
- ZONE_NORMAL:这个区包含的都是能正常映射的页
- ZONE_HIGHMEM:这个区包含“高端内存”,其中的页并能不永久地映射到内核地址空间
字(word):在计算机中,一串数码作为一个整体来处理或运算的,称为一个计算机字,简称字。在计算机的运算器、控制器中,通常都是以字为单位进行传送的。
字节(byte):字节是指一小组相邻的二进制数码。它是构成信息的一个小单位,并作为一个整体来参加操作,比字小,是构成字的单位。
6.3 虚拟地址空间
以进程号为1的进程为例,如下图:
cd /proc/1 # 进程1的目录 pmap -x 1 # 查看报告进程的内存映射关系
- 通过上图,可以知道程序进程占的内存空间段是怎样的关系
- 对于每一个程序进程都会有自己的虚拟内存空间地址
- 通过这种方式可以明显的知道占用内存的情况
- total:进程占内存的大小
- Kbytes:映像大小
- RSS:驻留集大小
- Dirty:脏页大小
- Mode:映像权限
- Mapping:映像支持文件【anon为已分配内存 stack为程序堆栈】
pmap -d 1 # 分析进程服务对应的虚拟地址段
查看映射关系(通过对应的地址空间寻址跟物理地址页做映射)
32位和64位操作系统内存有什么区别?
- 32位只支持4G内存
- 支持4KB的页
- 64位可以超过4G内存
- 一般支持8KB的页
- 问题在于对应页的个数、寻址空间比以前大
- 一般来说,服务器内存够大时,不用设置虚拟内存,映射的时候虚拟地址对应物理内存(详见上面的映射关系图)
6.4 主缺页和次缺页
cat /proc/meminfo # 查看内核使用内存情况的各种信息【各字段详解,转摘于其他博主】
6.4.1 主缺页
当 VP3 指向 DP1 关系不存在了(详见本文的映射图,虚拟地址空间指向磁盘),就是主缺页。对应Windows操作系统,就是硬错误。主缺页很多的时候,其实就表示swap数据读取到了内存。
sar -B 1 # 弱命令,只能看内存页的情况,free页,空缺页等等。也只能表示swap和内存的内存页的关系,无法得出其他结论
- majflt/s:主缺页
- fault/s:主缺页 + 次缺页 之和
- pgpgin/s:到内存两边页的关系
- pgpgout/s:到硬盘页的关系
如果发生主缺页时,说明VP3 指向 DP1 的映射关系发生了问题
- 缺页的时候,数据就会丢失
- 缺页中断,和网络没有关系
有主缺页只能得出,物理内存不足的时候,发生swap交换,swap用了多少,无法得知
结论:物理内存到虚拟地址空间或虚拟地址空间到磁盘的映射关系没有了,就会产生缺页。
6.4.2 次缺页
当 VP7 指向 PP3 关系不存在了(详见本文的映射图,虚拟地址空间指向物理内存),就是次缺页。对应Windows操作系统,就是软错误。
6.5 脏页
高速缓存,系统把读写频繁的事务在内存里面做了,提升读写速率。当修改了这部分数据的时候,系统就会给这个页做一个标记,标记成一个脏页,脏页就会带上一个叫dirty的标记。
脏页太多,会引起IO同步,牵涉到 IO 写入的性能 :
- 脏页是CPU的高速缓存写入内存的时候,因为数据不同步产生的
- 当内核发现有脏页的时候,为了保证跟磁盘数据保持一致性,就会进行数据同步,会牵涉到IO的写入
- 写入太多,就会对IO造成影响,从而引发一系列性能的问题
6.6 碎片
6.6.1 内部碎片的产生
所有的内存分配必须起始于可被4、8或16整除(视处理器体系结构而定)的地址或者因为MMU的分页机制的限制,决定内存分配算法仅能把预定大小的内存块分配给客户。
假设,当某个程序请求一个100字节的内存块时,因为没有合适大小的内存,所以它可能会获得128字节,或者更大一点的字节。四舍五入而产生多余空间叫内部碎片。
6.6.2 外部碎片的产生
频繁的分配与回收物理页面会导致大量的、连续且小的页面块夹杂在已分配的页面中间,就会产生外部碎片。
假设,有一块一共有100个单位的连续空闲内存空间,范围是0~99。从中申请一块内存,如10个单位,那么申请出来的内存块就为 0~9区间。继续申请一块内存,如5个单位,第二块得到的内存块就应该为10~14区间。如果把第一块内存块释放,在申请一块大于10个单位的内存块,比如20个单位,因为释放的内存块不能满足新的请求,所以只能从15开始分配20个单位的内存块。此时现在整个内存空间的状态是0~9空闲,10~14被占用,15~24被占用,25~99空闲。
- 0 ~ 9 就是一个内部碎片
- 如果10 ~ 14一直被占用,而以后申请的空间都大于10个单位,那么0 ~ 9就永远用不上,变成了外部碎片
6.7 内存的算法
6.7.1 slab Allocation算法
典型的应用场景是 memcached 内存存储机制 【用的比较多的redis缓存服务器中】
把申请的内存,根据指定的大小和增长因子(比如1.1或者1.2等)得到一组数据,来频繁的做一个内存的划分,如下图:
这个算法可能存在哪些问题(是否能满足各种场景)?
比如申请4个字节,需要分配88个字节的内存块,如申请89个字节,需要分配112个字节的内存块。因memcached 最小的分64个字节,然后往上细分。那么可以调整增长因子(如0.05等),来加大精准的分配。
6.7.2 内存动态管理策略 ---伙伴算法,如nginx
内核要分配一组连续的页框,必须建立一种健壮、高效的分配策略,来解决外部碎片。
分配策略的原理为二的N次方。比如:
- malloc(30),划分成1个32个字节的内存块,32[0,31]
- malloc(64),划分成两个32个字节的内存块,64[0,63]
- malloc(7),划分32太大,32划分成两个16,16还是很大,划分成4个8的内存块,8[32,39]
优点:可实现合理的内存申请和一些动态组装
缺点:大的内存分配不佳,存在较大的浪费,比如:
- 申请257byte,需要考虑分512byte
- 申请1030byte,需要考虑分2048byte
因此,nginx并没有使用纯粹的伙伴算法,只适合给小块的内存使用(如7个字节,16个字节,32个字节),效率很高,会让内存精打细算。
6.8 swap的使用问题
6.8.1 swap用到一定量会比较好
swap 是用的多好,还是用的少好?这个问题没有绝对的多好与坏少好,用到一定量会比较好。
就好比买房,一部分存款,一部分贷款比较合适一样(在自己的偿还范围内) ,对应到物理内存与swap,只要 buffer+cache 有能力偿还swap.used 所使用的内存即可。
buffer+cache = swap.used ,这样的数据,是否能接受?
通过数据来分析,没有太大的问题,可以接受。唯一需要担心的是崩盘,物理内存还不起swap已使用的内存。
6.8.2 利用使用率公式来分析,swap使用是否正常
内存使用率=(mem.used + swap.used)/(mem.total+swap.total)
大量使用swap 内存,说明有大量的从swap,写入到磁盘或从磁盘读取到swap的数据,磁盘 IO 过于繁忙出现阻塞,要和si、so、bi、bo以及wa%结合来分析,才能做结论。
6.9 内存监控命令
for pid in `ls /proc | grep "^[0-9]"`; do cat /proc/$pid/status | grep VmRSS | awk '{print $2}';done # 进程使用的常驻内存
cat /proc/meminfo | grep -i page # slaptop pagetable使用
pageTables:内核需要维护对应的内存结构和分配点信息的时候,需要把对象的信息缓存住,缓存住的映射表都存储在pageTables里面。所以在内存分析的时候,需要把pageTables 消耗算进去,得到总的内存消耗是多少
内存监控分析命令:
vmstat
free
dstat -t -s -m
tsar --mem --swap
ps
dstat -top-mem
top
cat /proc/1/status
pmap -d 1
性能分析与诊断,最终问题都会定位到具体的进程,再对具体的进程进行问题定位分析与优化。
七、内存总结
7.1 free 命令持续监控
- free -m -s 1 # 每秒执行一次free命令
- watch -n 1 'free -m' # watch可以帮你监测一个命令的运行结果,省去一遍遍的手动运行,在Linux下,watch是周期性的执行下个程序,并全屏显示执行的结果
- while true; do date;free -m; sleep 1;done; # 每秒执行一次free并打上时间戳
7.2 进程的内存使用
ps aux | grep -E "http|PID"
- %mem,物理内存占用内存的比分比
- VSZ,虚拟内存大小
- RSS,物理内存大小
cat /proc/1/status # 查看进程的内存信息
- VmPeak 进程占用峰值,占用内存最高的值
- VmSize 进程虚拟内存大小,进程内存的大小
- VmLck 进程锁定的物理内存大小,不会交换到磁盘
- VmHWM 文件内存映射和匿名内存映射的内存大小
- VmRSS 当前常驻内存,实际使用物理内存大小
- VmData 数据段内存大小,查程序的变量,常量,,申请内存的分配
- VmStk 进程在用户态的堆栈内存使用大小
- VmExe 可执行的虚拟内存大小
- VmLib lib库
- VmPTE 页表
结合分析的时候,需要拿对应PID的status文件与pmap命令进行组合的进程分析:
pmap -x 1 # 进程内存分析
- Kbytes 虚拟内存的数据
- RSS 物理内存的数据
- Dirty 脏页需要同步的数据
- Mode 最新的状态
- offset 内存的偏移位
- Mapping 映射到哪里,并且花的时间比较多
7.3 内存内核介绍
linux 系统全局搜索commit 文件的路径,grep commit ./* -R -n
vim ./sysctl/vm.txt +48 # 定位到某一行
系统安全策略:
sar -r 1 vm.overcommit_memory # 查看内存是否允许超载
- 等于0 允许内存超载
- echo 2 > /proc/sys/vm/overcommit_memory
- 等于2 不允许内存超载
- 等于1 通过科学计数法进行设置
Linux内核在线文档http://lxr.free-electrons.com/
Linux内核在线文档https://lxr.missinglinkelectronics.com/+trees