[转帖]性能之内存篇

性能,之内 · 浏览次数 : 0

小编点评

**内存性能分析** **1. 系统内存使用情况** 使用 `free` 和 `top` 命令查看系统整体的内存使用情况: ``` $ free Mem: 7743608 total, 7743608 used, 0 free Swap: 0 used, 0 free ``` **2. 进程内存使用情况** 使用 `vmstat` 命令查看一段时间的进程内存使用情况: ``` $ vmstat 1 # pid user system total used free 1 4988 257 131 120 33 ``` 从输出中可以看出,当前进程使用了 120 字节的内存。 **3. Swap 使用情况** 使用 `pidstat` 命令查看一段时间的进程 Swap 使用情况: ``` $ pidstat 1 # pid name pid size share free 1 4988 init 1 4096 32 288 ``` 从输出中可以看出,当前进程使用了 32 字节的 Swap 空间。 **4. 详细分析** 以下是一些详细的分析: * **系统内存使用:** 7743608 字节,剩余 7743608 字节。 * **进程内存使用:** 120 字节。 * **Swap 使用:** 32 字节。 * **内存分配分析:** 应用程序分配了 120 字节的内存。 * **缓存 / 缓冲区分析:** 应用程序使用了 32 字节的缓存和缓冲区。 * **具体进程的内存使用分析:** 应用程序使用了 120 字节的内存。 **性能瓶颈分析** 根据以上分析,内存性能瓶颈可能来自于: * 应用程序分配的内存不足。 * 应用程序使用了大量的缓存和缓冲区。 * 应用程序使用了大量的 Swap 空间。

正文

http://www.manongjc.com/detail/62-xzlnozethfhhibi.html

 

 
本文章向大家介绍性能之内存篇,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
 

最近笔者在看性能分析相关的是知识,就特意针对内存整理了这一篇文章,在这里笔者主要从下面三个方面来介绍这方面的知识: 1.内存的作用是什么,他在操作系统中的基础知识都有哪一些? 2.查看内存和内存相关问题涉及到的工具都有哪一些,他们的使用方式是什么样子的? 3.碰到内存问题的时候,我们需要怎么去定位呢?

一、内存的基础知识

1.内存的作用:主要用来存储系统和应用程序的指令、数据、缓存等,一般分为物理内存和虚拟内存。

2.物理内存

也称为主存,大多数计算机用的主存都是动态随机访问内存(DRAM),只有内核才可以直接访问物理内存。

3.虚拟内存:

Linux 内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的,这样,进程就可以很方便地访问这些虚拟内存。

 

备注:进程在用户态时,只能访问用户空间内存,只有进入内核态后,才可以访问内核空间内存。虽然每个进程的地址空间都包含了内核空间,但这些内核空间,其实关联的都是相同的物理内存,这样以来进程切换到内核态后,就可以很方便地访问内核空间内存。)

虚拟内存的分布介绍:

 
1. 栈内存:由系统自动分配和管理。
一旦程序运行超出了这个局部变量的作用域,栈内存就会被系统自动回收,所以不会产生内存泄漏的问题。
2. 堆内存:由应用程序自己来分配和管理。
除非程序退出,这些堆内存并不会被系统自动释放,而是需要应用程序明确调用库函数 free() 来释放它们。
如果应用程序没有正确释放堆内存,就会造成内存泄。
3. 只读段:包括程序的代码和常量,由于是只读的,不会再去分配新的内存,所以也不会产生内存泄漏。
4. 数据段:包括全局变量和静态变量,这些变量在定义时就已经确定了大小,所以也不会产生内存泄漏。
5. 内存映射段:包括动态链接库和共享内存,其中共享内存由程序动态分配和管理。
如果程序在分配后忘了回收,就会导致跟堆内存类似的泄漏问题。

4.内存映射:不是所有的虚拟内存都会分配物理内存,只有那些实际使用的虚拟内存才分配物理内存,并且分配后的物理内存,是通过内存映射来管理的。

 

备注:TLB 是 MMU 中页表的高速缓存,是CPU直接访问的地方。由于进程的虚拟地址空间是独立的,而 TLB 的访问速度又比 MMU 快得多,可以通过减少进程的上下文切换,减少 TLB 的刷新次数,这样来提高 TLB 缓存的使用率,进而提高 CPU 的内存访问性能。)

5.内存的分配和释放:

1)内存分配:

对小块内存(小于 128K),C 标准库使用 brk() 来分配,也就是通过移动堆顶的位置来分配内存,这些内存释放后并不会立刻归还系统,而是被缓存起来,这样就可以重复使用。

brk() 方式的内存:
优点:可以减少缺页异常的发生,提高内存访问效率。
缺点:由于这些内存没有归还系统,在内存工作繁忙时,频繁的内存分配和释放会造成内存碎片。

对于大块内存(大于 128K),则直接使用内存映射 mmap() 来分配,也就是在文件映射段找一块空闲内存分配出去。mmap() 方式分配的内存,会在释放时直接归还系统,所以每次 mmap 都会发生缺页异常。

mmap() 方式分配的内存:
优点:内存充足时,可以一次性分配好内存。
缺点:在内存工作繁忙时,频繁的内存分配会导致大量的缺页异常,使内核的管理负担增大。

备注:当这两种调用发生后,其实并没有真正分配内存,都只在首次访问时才分配,也就是通过缺页异常进入内核中,再由内核来分配内存。

2)内存释放:

在发现内存紧张时,系统就会通过一系列机制来回收内存,通常是下面这三种方式:

  1. 内存回收:比如使用 LRU(Least Recently Used)算法,回收最近使用最少的内存页面。

内存回收主要有两种方式:

方式一:直接内存回收:有新的大块内存分配请求,但是剩余内存不足,这个时候系统就需要回收一部分内存(比如前面提到的缓存),进而尽可能地满足新内存请求,这个过程通常被称为直接内存回收。 方式二定期回收内存:一个专门的内核线程用来定期回收内存,也就是 kswapd0。为了衡量内存的使用情况,kswapd0 定义了三个内存阈值(watermark,也称为水位),分别是页最小阈值(pages_min)、页低阈值(pages_low)和页高阈值(pages_high),剩余内存,则使用 pages_free 表示。

备注:这个页低阈值,其实可以通过内核选项 /proc/sys/vm/min_free_kbytes 来间接设置。)

kswapd0 定期扫描内存的使用情况,并根据剩余内存落在这三个阈值的空间位置,进行内存的回收操作。

 

回收过程:一旦剩余内存小于页低阈值,就会触发内存的回收。

在内存资源紧张时,Linux 通过直接内存回收和定期扫描的方式,来释放文件页和匿名页,以便把内存分配给更需要的进程使用。 文件页的回收比较容易理解,直接清空缓存,或者把脏数据写回磁盘后,再释放缓存就可以了。 对不常访问的匿名页,则需要通过 Swap 换出到磁盘中,这样在下次访问的时候,再次从磁盘换入到内存中就可以了。 (备注:开启 Swap 后,你可以设置 /proc/sys/vm/min_free_kbytes ,来调整系统定期回收内存的阈值,也可以设置 /proc/sys/vm/swappiness ,来调整文件页和匿名页的回收倾向。)

ii.通过Swap回收不常访问的内存:把不常用的内存通过交换分区直接写到磁盘中,通常会用到交换分区(以下简称 Swap),Swap 把这些不常访问的内存先写到磁盘中,然后释放这些内存,给其他更需要的进程使用,再次访问这些内存时,重新从磁盘读入内存就可以了。

 

Swap :就是把一块磁盘空间当成内存来用,它可以把进程暂时不用的数据存储到磁盘中(这个过程称为换出),当进程访问这些内存时,再从磁盘读取这些数据到内存中(这个过程称为换入)。通常只在内存不足时,才会发生 Swap 交换,并且由于磁盘读写的速度远比内存慢,Swap 会导致严重的内存性能问题。

# 创建Swap文件
$ fallocate -l 8G /mnt/swapfile
# 修改权限只有根用户可以访问
$ chmod 600 /mnt/swapfile
# 配置Swap文件
$ mkswap /mnt/swapfile
# 开启Swap
$ swapon /mnt/swapfile
# 关闭SWAP
$ swapoff -a && swapon -a

iii.OOM(Out of Memory)杀死进程:内存紧张时系统还会通过 OOM ,直接杀掉占用大量内存的进程。

OOM(Out of Memory):是内核的一种保护机制,它监控进程的内存使用情况。
评分规则:使用 oom_score 为每个进程的内存使用情况进行评分:
1.一个进程消耗的内存越大,oom_score 就越大;
2. 一个进程运行占用的 CPU 越多,oom_score 就越小。
进程的 oom_score 越大,代表消耗的内存越多,也就越容易被 OOM 杀死,从而可以更好保护系统。

备注:管理员可以通过 /proc 文件系统,手动设置进程的 oom_adj ,从而调整进程的 oom_score。

# oom_adj 的范围是 [-17, 15],数值越大,表示进程越容易被 OOM 杀死;
# 数值越小,表示进程越不容易被 OOM 杀死,其中 -17 表示禁止 OOM。
echo -16 > /proc/$(pidof sshd)/oom_adj

6. buffer与cache:

Buffers: 是内核缓冲区用到的内存,对应的是 /proc/meminfo 中的 Buffers 值。 Buffers 是对原始磁盘块的临时存储,也就是用来缓存磁盘的数据,通常不会特别大(20MB 左右)。这样,内核就可以把分散的写集中起来,统一优化磁盘的写入,比如可以把多次小的写合并成单次大的写等等。 Cache :是内核页缓存和 Slab 用到的内存,对应的是 /proc/meminfo 中的 Cached 与 SReclaimable 之和。

Cached :从磁盘读取文件的页缓存,也就是用来缓存从文件读取的数据。下次访问这些文件数据时,就可以直接从内存中快速获取,而不需要再次访问缓慢的磁盘。

 

Slab:包括两部分其中的可回收部分用SReclaimable记录而不可回收部分,用 SUnreclaim 记录。

buffers:  Memory used by kernel buffers (Buffers in /proc/meminfo)

cache: Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
buff/cache: Sum of buffers and cache 

Buffers %lu
    Relatively temporary storage for raw disk blocks that shouldn't get tremendously large (20MB or so).
Cached %lu
   In-memory cache for files read from the disk (the page cache).  Doesn't include SwapCached.
...
 %lu (since Linux 2.6.19)
    Part of Slab, that might be reclaimed, such as caches. 
SUnreclaim %lu (since Linux 2.6.19)
    Part of Slab, that cannot be reclaimed on memory pressure.

Cache 和Buffer区别:

Buffer 是对磁盘数据的缓存,而 Cache 是文件数据的缓存,它们既会用在读请求中,也会用在写请求中。

Buffer 既可以用作“将要写入磁盘数据的缓存”,也可以用作“从磁盘读取数据的缓存”。Cache 既可以用作“从文件读取数据的页缓存”,也可以用作“写文件的页缓存”。

理论上,一个文件读首先到Block Buffer, 然后到Page Cache。有了文件系统才有了Page Cache,在老的Linux上这两个Cache是分开的。那这样对于文件数据,会被Cache两次。这种方案虽然简单,但低效,后期Linux把这两个Cache统一了。对于文件,Page Cache指向Block Buffer,对于非文件则是Block Buffer。这样就如文件实验的结果,文件操作,只影响Page Cache,Raw操作,则只影响Buffer。比如一此VM虚拟机,则会越过File System,只接操作 Disk, 常说的Direct IO.

备注:磁盘是一个块设备,可以划分为不同的分区;在分区之上再创建文件系统,挂载到某个目录,之后才可以在这个目录中读写文件。在读写普通文件时,会经过文件系统,由文件系统负责与磁盘交互;而读写磁盘或者分区时,就会跳过文件系统,也就是所谓的“裸I/O“。这两种读写方式所使用的缓存是不同的,也就是文中所讲的 Cache 和 Buffer 区别。)

 

缓存的命中率:所谓缓存命中率,是指直接通过缓存获取数据的请求次数,占所有数据请求次数的百分比。命中率越高,表示使用缓存带来的收益越高,应用程序的性能也就越好。

二、工具和命令介绍

1.free:

# Mem:物理内存,Swap:交换分区
# total: 内存的总大小;
# used:是已使用内存的大小,包含了共享内存; 
# free:未使用内存的大小
# shared:是共享内存的大小
# buff:buffer的大小
# cache: cache的大小
# available: 新进程可用内存的大小
$ free
              total        used        free      shared  buff/cache   available
Mem:        8169348      263524     6875352         668     1030472     7611064
Swap:             0           0           0

2.top

# 按下M切换到内存排序
$ top
...
KiB Mem :  8169348 total,  6871440 free,   267096 used,  1030812 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  7607492 avail Mem

# VIRT: 是进程虚拟内存的大小,只要是进程申请过的内存,即便还没有真正分配物理内存,也会计算在内
# RES: 是常驻内存的大小,也就是进程实际使用的物理内存大小,但不包括 Swap 和共享内存。
# SHR: 是共享内存的大小,比如与其他进程共同使用的共享内存、加载的动态链接库以及程序的代码段等。
# MEM: 是进程使用物理内存占系统总内存的百分比。
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
  430 root      19  -1  122360  35588  23748 S   0.0  0.4   0:32.17 systemd-journal
 1075 root      20   0  771860  22744  11368 S   0.0  0.3   0:38.89 snapd
...

3.vmstat

# 每隔1秒输出1组数据
# bi 和 bo 则分别表示块设备读取和写入的大小,单位为块 / 秒。
# 因为 Linux 中块的大小是 1KB,所以这个单位也就等价于 KB/s。
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
0  0      0 7743608   1112  92168    0    0     0     0   52  152  0  1 100  0  0
 0  0      0 7743608   1112  92168    0    0     0     0   36   92  0  0 100  0  0

内存的 free 列在不停的变化,并且是下降趋势;而 buffer 和 cache 基本保持不变。未使用内存在逐渐减小,而 buffer 和 cache 基本不变,这说明,系统中使用的内存一直在升高,但这并不能说明有内存泄漏,因为应用程序运行中需要的内存也可能会增大。

4.cachestat /cachetop

cachestat 提供了整个操作系统缓存的读写命中情况。

cachetop 提供了每个进程的缓存命中情况。

# TOTAL :表示总的 I/O 次数
# MISSES ,表示缓存未命中的次数
# HITS ,表示缓存命中的次数;
# DIRTIES, 表示新增到缓存中的脏页数;
# BUFFERS_MB 表示 Buffers 的大小,以 MB 为单位;
# CACHED_MB 表示 Cache 的大小,以 MB 为单位。
$ cachestat 1 3
   TOTAL   MISSES     HITS  DIRTIES   BUFFERS_MB  CACHED_MB
       2        0        2        1           17        279
       2        0        2        1           17        279
       2        0        2        1           17        279
 # READ_HIT 和 WRITE_HIT ,分别表示读和写的缓存命中率
$ cachetop
11:58:50 Buffers MB: 258 / Cached MB: 347 / Sort: HITS / Order: ascending
PID      UID      CMD              HITS     MISSES   DIRTIES  READ_HIT%  WRITE_HIT%
   13029 root     python                  1        0        0     100.0%       0.0%

5. pcstat


$ pcstat /bin/ls
+---------+----------------+------------+-----------+---------+
| Name    | Size (bytes)   | Pages      | Cached    | Percent |
|---------+----------------+------------+-----------+---------|
| /bin/ls | 133792         | 33         | 0         | 000.000 |
+---------+----------------+------------+-----------+---------+

6.strace // 观察系统调用


# strace -p $(pgrep app)
strace: Process 4988 attached
restart_syscall(<... resuming interrupted nanosleep ...>) = 0
openat(AT_FDCWD, "/dev/sdb1", O_RDONLY|O_DIRECT) = 4
mmap(NULL, 33558528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f448d240000
read(4, "8vq213314264u3734336K22425@37112522262252q221n030225bD252266@J"..., 33554432) = 33554432
write(1, "Time used: 0.948897 s to read 33"..., 45) = 45
close(4)                                = 0

从 strace 的结果可以看到,案例应用调用了 openat 来打开磁盘分区 /dev/sdb1,并且传入的参数为 O_RDONLY|O_DIRECT(中间的竖线表示或)。O_RDONLY 表示以只读方式打开,而 O_DIRECT 则表示以直接读取的方式打开,这会绕过系统的缓存。

7.memleak

memleak 可以跟踪系统或指定进程的内存分配、释放请求,然后定期输出一个未释放内存和相应调用栈的汇总情况(默认 5 秒)。

8.sar

#kbcommit,表示当前系统负载需要的内存。它实际上是为了保证系统内存不溢出,对需要内存的估计值。
# commit,就是这个值相对总内存的百分比。
# kbactive,表示活跃内存,也就是最近使用过的内存,一般不会被系统回收。
# kbinact,表示非活跃内存,也就是不常访问的内存,有可能会被系统回收。
# kbmemfree:剩余内存
# 间隔1秒输出一组数据
# -r表示显示内存使用情况,-S表示显示Swap使用情况
$ sar -r -S 1
04:39:56    kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
04:39:57      6249676   6839824   1919632     23.50    740512     67316   1691736     10.22    815156    841868         4

04:39:56    kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
04:39:57      8388604         0      0.00         0      0.00

04:39:57    kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
04:39:58      6184472   6807064   1984836     24.30    772768     67380   1691736     10.22    847932    874224        20

04:39:57    kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
04:39:58      8388604         0      0.00         0      0.00
…
04:44:06    kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
04:44:07       152780   6525716   8016528     98.13   6530440     51316   1691736     10.22    867124   6869332         0

04:44:06    kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
04:44:07      8384508      4096      0.05        52      1.27

三、

1. 分析内存的性能瓶颈,可以按照下面的指标依次判断:

首先,是系统内存使用情况,比如已用内存、剩余内存、共享内存、可用内存、缓存和缓冲区的用量等。
其次,是进程内存使用情况,比如进程的虚拟内存、常驻内存、共享内存以及 Swap 内存、缺页异常等。
再次,就是 Swap 的使用情况,比如 Swap 的已用空间、剩余空间、换入速度和换出速度等。
 

2.按照下面的几个步骤进行依次分析:

首先,用 free 和 top,查看系统整体的内存使用情况。
接着,用 vmstat 和 pidstat,查看一段时间的趋势,从而判断出内存问题的类型。
最后进行详细分析,比如内存分配分析、缓存 / 缓冲区分析、具体进程的内存使用分析等。
 

参考资料:

《Operating System Concepts》

https://blog.holbertonschool.com/hack-the-virtual-memory-malloc-the-heap-the-program-breakLinux 性能优化实战

与[转帖]性能之内存篇相似的内容:

[转帖]性能之内存篇

http://www.manongjc.com/detail/62-xzlnozethfhhibi.html 本文章向大家介绍性能之内存篇,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。 最近笔者在看性能分析相关的是知识,就特意针对内存整

[转帖]Linux性能调优之内存负载调优的一些笔记

https://zhuanlan.zhihu.com/p/548770928 写在前面 整理一些Linux内存调优的笔记,分享给小伙伴 博文没有涉及的Demo,理论方法偏多,可以用作内存调优入门 博文内容涉及: Linux内存管理的基本理论 寻找内存泄露的进程 内存交换空间调优 不同方式的内存回收

[转帖]Linux性能优化和内核观测 - 内存篇(一)

内存虚拟内存Linux 采用的是​​虚拟内存​​机制,每个进程都有自己的虚拟内存地址空间,仅当实际使用内存的时候才会映射到物理内存地址之上。这种设计提供了物理内存的超额分配,Linux 中的内存管理机制包括页换出守护进程(page out daemon)、物理换页设备(swap device),以及

[转帖]java性能分析之火焰图

http://t.zoukankan.com/lemon-le-p-13820204.html 原由 最近因为kafka、zookeeper、ES和相关的Java应用的内存问题搞的头大,做运维将近4年,对Java调优、性能方面的知识了解的少之又少,是时候下定决心来对他多一个学习了。不能一口吃成一个胖

[转帖]Nginx性能优化-CPU篇

性能优化方法论 软件层面提升硬件使用率 增大CPU的利用率 增大内存的利用率 增大硬盘IO的利用率 增大网络带宽的利用率 提升硬件 网卡:万兆网卡 硬盘:固体硬盘,关注IOPS和BPS指标 CPU:更快主频,更多核心,更大缓存,更优架构 内存:更快访问速度 超出硬件性能上限后使用DNS CPU基本知

[转帖]Nginx性能优化-TCP篇

https://www.cnblogs.com/Otiger/p/16220187.html 性能优化方法论 软件层面提升硬件使用率 增大CPU的利用率 增大内存的利用率 增大硬盘IO的利用率 增大网络带宽的利用率 提升硬件 网卡:万兆网卡 硬盘:固体硬盘,关注IOPS和BPS指标 CPU:更快主频

[转帖]《Linux性能优化实战》笔记(七)—— CPU瓶颈快速分析及性能优化思路

相当于是前面篇章的小结 一、 CPU 性能指标 常见指标包括: 平均负载CPU 使用率(user、iowait、system、软硬中断等)进程上下文切换(自愿、非自愿)CPU 缓存的命中率 CPU 的处理速度就比内存的访问速度快得多。这样,CPU 在访问内存的时候,免不了要等待内存的响应。为了协调这

[转帖]JVM内存非典型术语介绍(shallow/retained/rss/reserved/committed)

https://www.jianshu.com/p/871d6bb3a32d 背景 ​ 在服务器性能优化内存这一项时,有一些现象很诡异。如top显示的RES很大,但是实际jvm堆内存占用很小,同时使用nmt发现committed更大。所以决定写这篇wiki大概介绍一下 JVM中如何计算一个对象的实际

[转帖]CPU性能监控之三-----非Numa架构的进程绑定

CPU性能监控之三 非Numa架构的进程绑定 https://blog.51cto.com/hl914/1557740 上一篇重点在Numa架构下如果绑定,这篇就说说在非numa架构下常用的绑定吧。 使用taskset这个命令进行绑定,这个命令无法对内存进行限制,所以,如果有特殊需要,也可以使用Nu

[转帖]JVM优化之调整大内存分页(LargePage)

转自:http://cjjwzs.iteye.com/blog/1059381 本文将从内存分页的原理,如何调整分页大小两节内容,向你阐述LargePage对JVM的性能有何提升作用,并在文末点明了大内分页的副作用。OK,让我们开始吧! 内存分页大小对性能的提升原理 首先,我们需要回顾一小部分计算机