Linux 性能优化实战
倪朋飞
资深 Linux 专家,Kubernetes 项目维护者
87256 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 65 讲
结束语 (1讲)
Linux 性能优化实战
15
15
1.0x
00:00/00:00
登录|注册

18 | 案例篇:内存泄漏了,我该如何定位和处理?

不会导致内存泄漏
只读段、数据段、内存映射段
需要调用 malloc() 分配,free() 释放
由应用程序自己分配和管理
超出作用域时自动回收
由系统自动分配和管理
是否有其他更好的修复方法
使用 memleak 工具检查内存泄漏
在多线程程序中注意内存访问和释放
在每个异常处理路径和成功路径上释放内存
养成良好的编程习惯
定位泄漏源并修复
使用 memleak 工具跟踪内存分配和释放
使用 vmstat 观察内存变化趋势
其他内存段
堆内存
栈内存
可能引发严重性能问题
可能导致系统内存耗尽
系统无法重新分配泄漏的内存
无法访问未释放的内存
思考
修复内存泄漏
定位和处理内存泄漏
内存的分配和回收
内存泄漏的危害
内存泄漏问题

该思维导图由 AI 生成,仅供参考

你好,我是倪朋飞。
通过前几节对内存基础的学习,我相信你对 Linux 内存的工作原理,已经有了初步了解。
对普通进程来说,能看到的其实是内核提供的虚拟内存,这些虚拟内存还需要通过页表,由系统映射为物理内存。
当进程通过 malloc() 申请虚拟内存后,系统并不会立即为其分配物理内存,而是在首次访问时,才通过缺页异常陷入内核中分配内存。
为了协调 CPU 与磁盘间的性能差异,Linux 还会使用 Cache 和 Buffer ,分别把文件和磁盘读写的数据缓存到内存中。
对应用程序来说,动态内存的分配和回收,是既核心又复杂的一个逻辑功能模块。管理内存的过程中,也很容易发生各种各样的“事故”,比如,
没正确回收分配后的内存,导致了泄漏。
访问的是已分配内存边界外的地址,导致程序异常退出,等等。
今天我就带你来看看,内存泄漏到底是怎么发生的,以及发生内存泄漏之后该如何排查和定位。
说起内存泄漏,这就要先从内存的分配和回收说起了。

内存的分配和回收

先回顾一下,你还记得应用程序中,都有哪些方法来分配内存吗?用完后,又该怎么释放还给系统呢?
前面讲进程的内存空间时,我曾经提到过,用户空间内存包括多个不同的内存段,比如只读段、数据段、堆、栈以及文件映射段等。这些内存段正是应用程序使用内存的基本方式。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了如何定位和处理内存泄漏的问题。作者首先回顾了内存的分配和回收方式,包括栈和堆内存的分配与释放。然后详细讨论了内存泄漏的危害,指出内存泄漏会导致系统性能问题,并介绍了如何使用vmstat工具观察内存变化情况。接着,通过一个斐波那契数列的案例演示了如何检测内存泄漏并进行定位和处理。最后,作者提供了在Ubuntu 18.04系统上运行案例的具体步骤和命令。整体而言,本文以案例为引导,结合具体工具和命令,帮助读者了解内存泄漏问题的定位和处理方法。 文章通过介绍内存泄漏的危害、使用vmstat工具观察内存变化情况以及演示如何检测内存泄漏并进行定位和处理,为读者提供了全面的解决方案。同时,作者还提到了使用memleak工具来跟踪内存分配和释放请求,并指出了在容器中运行时可能遇到的问题以及解决方法。最后,文章总结了修复内存泄漏的方法,并鼓励读者养成良好的编程习惯,以避免内存泄漏的发生。整体而言,本文内容详实,适合开发人员和系统管理员阅读,对于定位和处理内存泄漏问题有很好的指导作用。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Linux 性能优化实战》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(125)

  • 最新
  • 精选
  • Scott
    我比较关心老版本的Linux怎么做同样的事,毕竟没有办法升级公司服务器的内核。

    作者回复: 另一个用的比较多的是valgrind

    2019-01-01
    3
    57
  • 睡在床板下
    谈谈自己生产环境运行3个月的内存泄露经验吧: 现象:服务程序运行90天,监控系统告警内存达到阈值,内存泄漏800M。现实:生产环境、难复现。 - 保存core文件。 统计top10 大小块内存分配百分比 - 发现20字节大小内存申请了 3700w次,大概700M - 通过工具搜索已有符号文件中大小为20字节的结构体、类,但是可能包含第三方库、组件没有符号文件,导致分析遇阻,未果 - 通过随机抽查20字节内存地址内容,希望找到有效信息,但几乎都是 0x00 0x10 0x00 , 没字符串,猜不出什么内容,未果 - 通过3700w次数申请,平均每小时17000次左右。 通过完善的日志系统,分析1w~3w量级的消息,大概4个,review代码,问题解决 - 问题定位总共花费了4个小时左右。分析内存泄漏工具、方法很多,但是我觉的更重要的是完善的监控系统和日志系统。

    作者回复: 谢谢分享!的确,完善的监控和日志可以更快排查和定位问题,我们专栏后面也有文章提到监控的一些思路。

    2020-07-20
    7
    34
  • Maxwell
    如果是java应用程序,也可以用这个方法定位么?

    作者回复: Java 看到的是JVM 的堆栈。其实,jmap这些Java原生的工具更好用

    2019-01-02
    6
    21
  • 阿卡牛
    老师,你这个例子是已经知道哪个进程有内存泄露了,请问如何找出哪个进程呢?

    作者回复: 去掉进程号选项

    2019-01-04
    4
    12
  • 姜小鱼
    老师,memleak只能检测用户程序的内存泄漏吧?如果检测内核态谋和模块内存泄漏呢,Kmemleak能否讲一下呢?

    作者回复: 也支持内核的,看它的源码可以发现,kmalloc/kfree/kmem_cache_alloc等等也都在TRACEPOINT_PROBE里面

    2019-05-07
    4
  • Vicky🐣🐣🐣
    1. 如果执行/usr/share/bcc/tools/memleak -a -p [pid] 就会报错Exception: Failed to attach BPF to uprobe 但是执行/usr/share/bcc/tools/memleak -a,就不会报错,但是里面并没有和app相关函数 2. free观察情况如下,新机器,并没有任何其他高占用内存的进程,很是奇怪 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 0 0 218244 112044 463144 0 0 21 31 148 344 1 0 99 0 0 0 0 0 218268 112044 463144 0 0 0 0 168 402 0 1 99 0 0 0 0 0 217928 112044 463144 0 0 0 7 182 427 1 0 99 0 0 0 0 0 217836 112044 463228 0 0 23 0 317 730 1 1 98 0 0 0 0 0 217836 112048 463236 0 0 0 17 186 437 1 0 99 0 0 0 0 0 215804 112052 463232 0 0 0 19 202 476 1 1 98 0 0 0 0 0 215860 112052 463240 0 0 0 5 221 490 1 1 99 0 0 0 0 0 217040 112056 463244 0 0 0 15 207 481 1 0 99 0 0 0 0 0 217040 112056 463244 0 0 0 0 156 363 0 0 100 0 0 0 0 0 76976 112056 463296 0 0 24 12 221 546 11 3 86 0 0 0 0 0 77008 112060 463316 0 0 0 11 178 407 1 1 98 0 0 0 0 0 75140 112060 463324 0 0 0 27 176 812 2 3 95 0 0 0 0 0 74584 112060 463328 0 0 0 7 174 819 1 1 98 0 0 0 0 0 74616 112060 463332 0 0 0 0 183 417 0 0 99 0 0 0 0 0 216884 112060 463332 0 0 0 83 176 403 1 0 98 1 0 0 0 0 216884 112064 463328 0 0 0 9 180 448 0 1 99 0 0 0 0 0 217012 112064 463336 0 0 0 4 193 452 0 1 99 0 0

    作者回复: 看一下内核配置开启CONFIG_UPROBE_EVENTS了吗?

    2019-02-23
    4
    3
  • Vicky🐣🐣🐣
    老师,很多同学都问这个问题了,麻烦解答一下吧 ubuntu 4.15.0-29 # /usr/share/bcc/tools/memleak -a -p 21642 Attaching to pid 21642, Ctrl+C to quit. perf_event_open(/sys/kernel/debug/tracing/events/uprobes/p__lib_x86_64_linux_gnu_libc_2_27_so_0x97070_21642_bcc_21882/id): Input/output error Traceback (most recent call last): File "/usr/share/bcc/tools/memleak", line 416, in <module> attach_probes("malloc") File "/usr/share/bcc/tools/memleak", line 406, in attach_probes pid=pid) File "/usr/lib/python2.7/dist-packages/bcc/__init__.py", line 989, in attach_uprobe raise Exception("Failed to attach BPF to uprobe") Exception: Failed to attach BPF to uprobe

    作者回复: 内核中需要开启 CONFIG_UPROBE_EVENTS=y

    2019-02-23
    4
    3
  • 唯安格
    老师,我运行:$ /usr/share/bcc/tools/memleak -a -p $(pidof app) 并没有看到内存泄漏的问题。之后还看了app的源码。源码内的确没有调用free()函数。请问这可能是什么情况? root@ubuntu:/# /usr/share/bcc/tools/memleak -p $(pidof app) -a Attaching to pid 84307, Ctrl+C to quit. [02:42:22] Top 10 stacks with outstanding allocations: [02:42:27] Top 10 stacks with outstanding allocations: [02:42:32] Top 10 stacks with outstanding allocations: [02:42:37] Top 10 stacks with outstanding allocations: [02:42:43] Top 10 stacks with outstanding allocations: [02:42:48] Top 10 stacks with outstanding allocations: [02:42:53] Top 10 stacks with outstanding allocations: [02:42:58] Top 10 stacks with outstanding allocations: [02:43:03] Top 10 stacks with outstanding allocations: ^Croot@ubuntu:/# docker exec app cat /app.c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> long long *fibonacci(long long *n0, long long *n1) { long long *v = (long long *) calloc(1024, sizeof(long long)); *v = *n0 + *n1; return v; } void *child(void *arg) { long long n0 = 0; long long n1 = 1; long long *v = NULL; for (int n = 2; n > 0; n++) { v = fibonacci(&n0, &n1); n0 = n1; n1 = *v; printf("%dth => %lld\n", n, *v); sleep(1); } } int main(void) { pthread_t tid; pthread_create(&tid, NULL, child, NULL); pthread_join(tid, NULL); printf("main thread exit\n"); return 0;

    作者回复: 去掉进程号选项-p试试?

    2019-03-12
    2
  • 元天夫
    还有一个很low的问题,Linux version 2.6.32-504.23.4.el6.x86_64 (mockbuild@c6b9.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-11),这个是我查看的内核信息,这个显示内核版本是4.4.7对吗?

    作者回复: 4.4.7是Red Hat产品的版本,内核版本是2.6.32

    2019-02-22
    2
    2
  • 元天夫
    老师,请教个问题,pmap -x下,看到有的输出项的脏页数比较大,有104万,这个算大吗

    作者回复: 看场景,比如一般的I/O密集型的应用,脏页大一些可能是正常的;但有些数据一致性要求比价高的应用,可能希望尽可能快的将数据落盘

    2019-02-22
    2
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部