Linux 内存性能优化 —— 高内存使用及内存泄漏排查
文章目录如何查看Linux内存的使用情况显示Linux整体内存使用:freebuff 和 cache是什么?查看进程的内存使用情况:top理解缓存在内存性能优化扮演的角色查看系统缓存命中情况:cachestat 和 cachetop如何查看Linux内存的使用情况显示Linux整体内存使用:free在Linux 系统中,我们可以使用free命令去查看当前系统的一个内存使用情况:ubuntu@VM-
文章目录
作者邮箱:2107810343@qq.com
时间:2021/05/1416:39
实现环境:Linux
系统:ubuntu 18.04
CPU:2核
内存大小:4G
如何查看Linux内存的使用情况
显示Linux整体内存使用:free
在Linux 系统中,我们可以使用free
命令去查看当前系统的一个内存使用情况:
ubuntu@VM-0-2-ubuntu:~/ByteTalk/Porxy$ free
total used free shared buff/cache available
Mem: 3875308 906836 866884 7004 2101588 2684856
Swap: 0 0 0
可以看到,free输出的是一个表格,其中数值都默认以字节为单位。表格总共有两行六列,分别是 Memory 和 Swap 两个的使用情况,每列的数据使用情况如下:
- total:总内存大小,博主这里是3875308字节,也就是3GB的空间,正好和进程3GB虚拟空间相对应
- used:已使用的内存大小,包含共享内存
- free:未使用内存的内存大小
- shared:共享内存大小
- buff/cache:缓存和缓冲区的大小
- available:新进程可使用的内存大小
这里我们可以看到,available 比 free 要大很多,这是因为其包含未使用的内存以及可回收的缓存。所以: 新进程可使用内存 = 未使用内存 + 可回收缓存
buff 和 cache是什么?
对于其他几个属性都是字面意思,很容易理解。这个buff 和 cache是干嘛的就很让人迷惑。
man free:
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
从手册中,我们可以看到buffer 和 cache的说明:
- Buffers 是内存缓冲区用到的内存,对应的是
/proc/meminfo
中的值 - Cache 是内核页缓存和 Slab 用到的内存,对应的是
/proc/meminfo
中的 Cached与SReclaimable之和
注:
- Buffers 是对原始磁盘块的临时存储,就是对磁盘数据的缓存,不仅用在读请求中,也会用在写请求中
- Cached 是从磁盘读/写文件时的页缓存。
- SReclaimable 是 Slab 的一部分。Slab 包括两部分,一个是可回收的部分,用SReclaimable记录;而不可回收部分,用SUnreclaim 记录
这里的buffer 和 cache用作缓存的区别是,buffer 用于磁盘块设备文件的缓存,块设备文件不同于普通文件,是Linux 文件系统的载体;而cache 用作的则是文件的缓存,在读写普通文件的时候,I/O请求会首先经过文件系统,然后由文件系统负责,来与磁盘交互。
查看进程的内存使用情况:top
free 工具显示的是整个系统的内存使用情况。如果你想查看进程的内存使用情况,可以使用 top 或者 ps 等工具。以下是 top 使用的例子:
ubuntu@VM-0-2-ubuntu:~/ByteTalk/Porxy$ top
top - 12:31:21 up 4 days, 13:22, 0 users, load average: 0.00, 0.00, 0.00
Tasks: 128 total, 1 running, 85 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.6 us, 0.6 sy, 0.0 ni, 98.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
# total memory:
KiB Mem : 3875308 total, 859736 free, 911556 used, 2104016 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 2680056 avail Mem
# process memory:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
22932 ubuntu 20 0 1522448 270180 31584 S 0.8 7.0 0:13.14 node
1777 root 20 0 985744 41884 14976 S 0.4 1.1 24:21.98 YDService
1873 root 20 0 502424 13252 3056 S 0.4 0.3 16:53.29 barad_agent
20719 root 20 0 0 0 0 I 0.4 0.0 0:00.02 kworker/u4:3
22904 ubuntu 20 0 794364 37724 28516 S 0.4 1.0 0:05.05 node
1 root 20 0 78060 6792 4336 S 0.0 0.2 0:13.39 systemd
在标记处total memory
开始的接下来两行其实也就是在调用free
,显示的是系统总的内存使用情况。
然后从标记处process memory
开始,就是每个进程的内存使用情况,比如:VIRT RES SHR 以及 %MEM:
- VIRT:进程虚拟内存的大小,只要是进程申请过的内存,即便是还没有真正分配物理内存,也会计算在内。
- RES:常驻内存的大小,也就是进程实际使用的物理内存大小,不包括SWAP 和共享内存
- SHR:共享内存大小,包括通过mmap申请的共享内存以及加载的动态链接库以及程序的代码段等
- %MEM:进程使用的物理内存占系统总内存的百分比
补:top命令的其他用法
输入top命令,按一下’M’可以快速查看内存占用由高到低的清空:
输入’P’则是可以查看CPU占用的由高到低:
或者我们可以按组合键’xb’,然后通过<>来手动选择排序的列。
理解缓存在内存性能优化扮演的角色
刚刚我们提到了缓存的这个概念。其利用了SRAM 设备与 ROM设备不同的访问速度来提高进程访问持久化资源的效率。
在评估缓存是否有用的时候,我们就不得不引入缓存命中率这个概念。所谓缓存命中率,是指直接通过缓存获取数据的请求次数,占所有数据请求次数的百分比。
命中率越高,表示使用缓存带来的收益越高,应用程序的性能也就越好。
查看系统缓存命中情况:cachestat 和 cachetop
- cachestat:提供了整个操作系统缓存的读写命中情况
- cachetop:提供了每个进程的缓存命中情况
要使用这两个工具,我们就需要先安装一下:
ubuntu@VM-0-2-ubuntu:~/ByteTalk/Porxy$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
ubuntu@VM-0-2-ubuntu:~/ByteTalk/Porxy$ echo "deb https://repo.iovisor.org/apt/xenial xenial main" | sudo tee /etc/apt/sources.list.d/iovisor.list
# 更新 apt 仓库
ubuntu@VM-0-2-ubuntu:~/ByteTalk/Porxy$ sudo apt-get update
ubuntu@VM-0-2-ubuntu:~/ByteTalk/Porxy$ sudo apt-get install -y bcc-tools libbcc-examples linux-headers-$(uname -r)
# 添加到系统PATH路径中
ubuntu@VM-0-2-ubuntu:~/ByteTalk/Porxy$ export PATH=$PATH:/usr/share/bcc/tools/
环境配置完成之后,我们运行一下cachestat 和 cachetop命令:
ubuntu@VM-0-2-ubuntu:/usr/share/bcc/tools$ sudo ./cachestat 1 3
HITS MISSES DIRTIES HITRATIO BUFFERS_MB CACHED_MB
42 0 0 100.00% 195 2009
3096 0 17 100.00% 195 2009
1203 0 1 100.00% 195 2009
其中每个属性的含义如下:
- HITS:表示缓存命中的次数
- MISSES:表示缓存未命中的次数
- DIRTIES:表示新增到缓存中的脏页数
- HITRATIO:缓存命中率
- BUFFERS_MB:表示buffers 的大小,以MB为单位
- CACHE_MB:表示Cache的大小,以MB为单位
我们再来看看cachetop的使用:
ubuntu@VM-0-2-ubuntu:/usr/share/bcc/tools$ sudo ./cachetop
这里我们就可以精确到每个进程了。
内存泄漏
内存泄漏起因
我们一般把程序的虚拟内存分为以下几个部分:堆栈、只读段、数据段以及内存映射段。
其中只有两个地方会发生内存泄漏:堆、内存映射段。
- 堆:堆内存由应用程序自己来分配和管理。除非程序退出,这些堆内存并不会被系统自动释放,而是需要库函数去调用free()自己释放,如果没有释放,就会造成内存泄漏。
- 内存映射段:包括动态链接库和共享内存,其中共享内存由程序动态分配和管理。所以,在程序分配后忘了回收,就会导致跟堆内存类似的泄漏问题。
内存泄漏会导致系统没有可用内存,不仅应用程序自己无法访问内存,系统也不能开启其他进程来使用。虽然,系统最终可用通过OOM机制来杀死进程,但是在这之前相当长一段的空白期,可能会导致非常严重的事故,导致严重的性能问题。
内存泄漏定位及排查
我们先用以下代码模拟以下内存泄漏:
void run()
{
for (int i = 0; i < 5; i++)
{
char *p = (char *)malloc(4096);
sleep(1);
}
for(;;) sleep(1);
}
int main()
{
run();
}
然后我们使用vmstat 命令去查看一下当前系统的内存使用情况:
ubuntu@VM-0-2-ubuntu:~/python_file$ vmstat 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
6 0 0 309592 232820 2213544 0 0 8 51 9 15 1 1 98 0 0
4 0 0 307772 232820 2213548 0 0 0 0 660 1157 0 0 99 0 0
0 0 0 306448 232820 2213572 0 0 0 24 899 1677 1 1 98 0 0
0 0 0 305860 232820 2213572 0 0 0 35 779 1390 0 1 99 0 0
可以看到,buff 和 cache两列的内容是基本保持不变的,free 列的数据是递减的。这种情况下,貌似是发生了内存泄漏,但是也不敢肯定,因为内存的开辟存在开辟回收的情况,可能是其他进程在申请内存。
所以我们需要使用一个新工具:memleak,其可以跟踪系统或者指定进程的内存分配、释放请求,然后定期食醋胡一个未释放内存和响应调用栈的汇总情况(默认 5秒)。
在命令行使用以下指令:
# -a 表示显示内阁内存分配请求的大小以及地址
# -p 指定案例应用的pid号
# 24483 进程pid号
ubuntu@VM-0-2-ubuntu:~/python_file$ sudo /usr/share/bcc/tools/memleak -a -p 24483
[14:30:41] Top 10 stacks with outstanding allocations:
addr = 56142d125ea0 size = 4096
addr = 56142d12aef0 size = 4096
addr = 56142d127ec0 size = 4096
addr = 56142d126eb0 size = 4096
addr = 56142d129ee0 size = 4096
addr = 56142d128ed0 size = 4096
24576 bytes in 6 allocations from stack
# 这里 run()+0x1f [test]
main+0x13 [test]
__libc_start_main+0xe7 [libc-2.27.so]
[unknown]
可以看到,是test 进程中的run函数造成的内存泄漏。我们接下来只用打开源代码修改就好了。
参考文献
[1] 倪朋飞.Linux性能优化实战.极客时间
[2] 罗剑锋.罗剑锋的C++实战笔记.极客时间
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)