夭兽啦,内存泄漏了怎么办
导读
作为DBA,如何快速确认Linux系统下是否有内存泄漏风险呢?
和叶师傅一起探索究竟。
下面全文建议横屏观看效果更佳。
什么是内存泄漏
wikipedia中这样定义内存泄漏的
在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。
内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。
简言之,我理解的内存泄漏是:
内存申请并用完后,没有被正常释放,而C/C++中又没有内存自动回收机制,这部分内存无法再次被重复利用,这些内存就像是进入了”内核黑洞“(这是我瞎造的名词),凭空消失了。
内存泄漏可能会导致相应的进程持续申请内存,最终导致触发OOM killer机制,该进程自身可能会也被杀掉。如果是MySQL 在没有设置双1时,还可能会导致数据丢失的风险。
应对内存泄漏的方法有:
重启进程,释放内存;
检查升级代码,修复bug。
如何确认内存泄漏风险
既然内存泄漏有如此风险,我们应该及早发现确定并提前处理,避免潜在风险。
来说说我的个人经验吧,下面的实验所用环境是aliyunOS,大概相对应于RHEL 7/CentOS 7。
[yejr@imysql.com ~]# cat /etc/redhat-release
Alibaba Cloud Enterprise Linux Server release 17.01.2 (Golden Toad)
[yejr@imysql.com ~]# uname -a
Linux zhishutang.com 3.10.0-514.2.3.al7.x86_64 #1 SMP Thu Jan 5 09:53:52 CST 2017 x86_64 x86_64 x86_64 GNU/Linux
首先,当前系统完全空闲,没运行任何内存高消耗进程:
[yejr@imysql.com ~]# free -h
total used free shared buff/cache available
Mem: 3.7G 67M 3.5G 360K 102M 3.5G
Swap: 0B 0B 0B
运行一个人为制造内存泄漏的进程,运行一段时间后,再看下内存使用情况:
[yejr@imysql.com ~]# free -h
total used free shared buff/cache available
Mem: 3.7G 2.2G 1.4G 360K 104M 1.4G
Swap: 0B 0B 0B
看看系统进程内存消耗情况:
[yejr@imysql.com ~]# top
top - 15:28:19 up 76 days, 17 min, 2 users, load average: 0.05, 0.05, 0.05
Tasks: 65 total, 2 running, 63 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 2.4 sy, 0.0 ni, 97.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3882068 total, 1555840 free, 2219108 used, 107120 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 1483188 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1582 root 20 0 2161324 2.050g 1008 R 4.0 55.4 0:13.44 memleak <---人为制造的内存泄漏进程
24021 polkitd 20 0 525836 8060 500 S 0.0 0.2 1:11.44 polkitd
12643 root 20 0 129028 5612 820 S 0.0 0.1 10:44.95 AliYunDun
当我们停止该进程后,内存消耗又恢复原样:
[yejr@imysql.com ~]# free -h
total used free shared buff/cache available
Mem: 3.7G 64M 3.5G 360K 104M 3.5G
Swap: 0B 0B 0B
从上面的测试过程中,我们能发现一个特征,那就是:buff/cache 列的值,相对于 used 的值小了很多,至少相差。
再来看多个mysqld进程启动前后的内存消耗对比。
所有mysqld进程未启动前:
[yejr@imysql.com ~]# free -h
total used free shared buff/cache available
Mem: 3.7G 62M 3.1G 360K 552M 3.4G
Swap: 0B 0B 0B
四个mysqld进程全部启动之后:
[yejr@imysql.com ~]# free -h
total used free shared buff/cache available
Mem: 3.7G 2.1G 601M 360K 1.0G 1.4G
Swap: 0B 0B 0B
我们看到,buff/cache 的值是 1.0G,而 used 是 2.1G,也是疑似有内存泄漏风险。
看看几个进程分别占用的内存比例:
[yejr@imysql.com ~]# top
top - 16:15:42 up 76 days, 1:04, 2 users, load average: 0.00, 0.01, 0.05
Tasks: 67 total, 2 running, 65 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.3 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3882068 total, 572780 free, 2184924 used, 1124364 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 1470612 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4952 mysql 20 0 4473076 733244 6188 S 0.0 18.9 0:00.54 mysqld <---MySQL 5.6
4950 mysql 20 0 4575432 524816 9184 S 0.0 13.5 0:00.62 mysqld <---MySQL 8.0
4949 mysql 20 0 4529040 457248 11164 S 0.0 11.8 0:00.49 mysqld <---MySQL 5.7
4951 mysql 20 0 4626516 430492 9876 S 0.0 11.1 0:01.35 mysqld <---Percona Server 5.724021 polkitd 20 0 525836 8060 500 S 0.0 0.2 1:11.47 polkitd
12643 root 20 0 129028 5836 1044 R 0.0 0.2 11:05.11 AliYunDun
备注:这四个mysqld进程的内存相关参数都一样。
innodb_buffer_pool_size = 2867M
read_rnd_buffer_size = 4M
join_buffer_size = 4M
sort_buffer_size = 4M
从上面的的现场我们似乎也能认为,MySQL 5.6版本比5.7、8.0要消耗更多内存;另外,同样是5.7版本,Percona Server内存消耗也要比官方社区版略小一点。
附录
模拟内存泄漏的C++代码
[yejr@imysql.com~] # cat memleak.cpp
#include <stdlib.h>
#include <iostream>
#include <unistd.h>
using namespace std;
void GetMemory(char *p, int num)
{
//只申请内存不释放
p = (char*)malloc(sizeof(char) * num);
}
int main(int argc,char** argv)
{
char *str = NULL;
cout<<"Memory leak test!"<<endl;
//每0.1秒调用一次
//运行一段时间后记得终止本程序
while(1){GetMemory(str, 4096); usleep(100); }
return 0;
}
延伸阅读
C/C++内存泄漏及检测,http://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html
在 Linux 平台中调试 C/C++ 内存泄漏方法,https://www.ibm.com/developerworks/cn/linux/l-cn-memleak/index.html
知识无界限,不再加原创
喜欢就转走,铁粉加密圈
好铁观音尽在
「老叶茶馆」
http://yejinrong.com