查看原文
其他

夭兽啦,内存泄漏了怎么办

和叶师傅学闽南话 老叶茶馆 2023-03-10

导读

作为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; }


延伸阅读



知识无界限,不再加原创

喜欢就转走,铁粉加密圈


好铁观音尽在

「老叶茶馆」

http://yejinrong.com

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存