栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

性能诊断分析 - 内存篇

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

性能诊断分析 - 内存篇

一、早期的内存使用与内存管理技术演变

在早期的计算机中,程序是直接运行在物理内存上的。换句话说,就是程序在运行的过程中访问的都是物理地址。如果这个系统只运行一个程序,那么只要这个程序所需的内存不要超过该机器的物理内存就不会出现问题,我们也就不需要考虑内存管理这个麻烦事了,反正就你一个程序,就这么点内存,吃不吃得饱那是你的事情了。然而现在的系统都是支持多任务,多进程的,这样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  【1. 文件节点,目录索引 2.   3. 是把所有的释放掉】
  • sync  ---内存的数据同步磁盘

释放后的内存,进入到了 free, used 相应的减少,如果没有进行sync 磁盘同步,那么释放掉的buffer和cache 空间就丢掉了,需要重启服务器

通常情况下,我们不应该为了free的空间而随意的去清理buffer和cache,治标不治本。当发生内存不足、应用获取不到可用内存、OOM错误等问题时,还是更应该去分析应用方面的东西。当前在无法避免的情况下,我们是可以临时清空,但问题终究需要彻底解决。

2.4 内存阈值定义

既然swap的作用是置换,那在分析内存阀值的时候,需要把swap 给算进去

  • 根据压测情况,系统资源情况,这样的实际情况来决定,没有固定的百分比
  • 内存的阈值定义,并不是拍脑袋说50% 70% 90%,而是要根据实际的业务场景而定

swap total 数据要小点,当swap 太大的时候,此时内存还没告警, io cpu 已经告警,使用数建议不超过4G,不然频繁置换,影响IO问题

  • 在当前时间节点,资源以不在是多么奢侈的事情,当服务器资源都已经在32G以上时,设置swap虚拟内存空间已经没有多大必要(很多企业的服务器已不再设置swap),当系统内存遇到瓶颈时,大量的内存置换,也会造成其他系统异常(如cpu、IO),一定要设置,建议设置2~4G即可。
2.5 swap 太大或太小会遇到的几个问题

2.5.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.5.2 swap 太小,套用公式是否合理

内存公式不需要变,物理内存足够大时,可以忽略swap。

3. 内存利用率瓶颈怎么去分析

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 虚拟内存

4. 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 有关。

%wa 有数值,bi和bo也有数值,是否就能推导IO有问题?

不一定,512个字节是一个设备块,从单一的数据(如%wa 99)来分析,并不算高 (512byte/s)
不能以一次99来分析IO有问题,还需要结合整理来进行分析。

4.3 其他的几个指标含义
  • 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不足

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/987859.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号