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

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

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

内存的分配和回收

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

全部留言(125)

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

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

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

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

    6
    31
  • Maxwell
    如果是java应用程序,也可以用这个方法定位么?

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

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

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

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

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

    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了吗?

    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

    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试试?

    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

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

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

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