内存泄漏了,该如何定位和处理?

本文是通过学习倪朋飞老师的《Linux性能优化实战》 :内存泄漏了,该如何定位和处理?

内存泄漏了,该如何定位和处理?

对普通进程来说,能看到的其实是内核提供的虚拟内存,这些虚拟内存还需要通过页表,由系统映射为物理内存。

当进程通过 malloc() 申请虚拟内存后,系统并不会立即为其分配物理内存,而是在首次访问时,才通过缺页异常陷入内核中分配内存。

为了协调 CPU 与磁盘间的性能差异,Linux 还会使用 Cache 和 Buffer ,分别把文件和磁盘读写的数据缓存到内存中。

对应用程序来说,动态内存的分配和回收,是既核心又复杂的一个逻辑功能模块。管理内存的过程中,也很容易发生各种各样的“事故”,比如:

  • 没正确回收分配后的内存,导致了泄漏。
  • 访问的是已分配内存边界外的地址,导致程序异常退出,等等。

说起内存泄漏,这就要先从内存的分配和回收说起了。

内存的分配和回收

用户空间内存包括多个不同的内存段,比如只读段、数据段、堆、栈以及文件映射段等。这些内存段正是应用程序使用内存的基本方式。

举个例子,在程序中定义了一个局部变量,比如一个整数数组 int data[64] ,就定义了 一个可以存储 64 个整数的内存段。由于这是一个局部变量,它会从内存空间的栈中分配内存。

栈内存由系统自动分配和管理。一旦程序运行超出了这个局部变量的作用域,栈内存就会被系统自动回收,所以不会产生内存泄漏的问题。

再比如,很多时候,我们事先并不知道数据大小,所以你就要用到标准库函数 malloc() 在程序中动态分配内存。这时候,系统就会从内存空间的堆中分配内存。

堆内存由应用程序自己来分配和管理。除非程序退出,这些堆内存并不会被系统自动释放,而是需要应用程序明确调用库函数 free() 来释放它们。如果应用程序没有正确释放堆内存,就会造成内存泄漏。
这是两个栈和堆的例子,那么,其他内存段是否也会导致内存泄漏呢?

  • 只读段,包括程序的代码和常量,由于是只读的,不会再去分配新的内存,所以也不会产生内存泄漏。
  • 数据段,包括全局变量和静态变量,这些变量在定义时就已经确定了大小,所以也不会产生内存泄漏。
  • 最后一个内存映射段,包括动态链接库和共享内存,其中共享内存由程序动态分配和管理。所以,如果程序在分配后忘了回收,就会导致跟堆内存类似的泄漏问题。

**内存泄漏的危害非常大,这些忘记释放的内存,不仅应用程序自己不能访问,系统也不能把它们再次分配给其他应用。**内存泄漏不断累积,甚至会耗尽系统内存。

虽然,系统最终可以通过 OOM (Out of Memory)机制杀死进程,但进程在 OOM 前,可能已经引发了一连串的反应,导致严重的性能问题。

比如,其他需要内存的进程,可能无法分配新的内存;内存不足,又会触发系统的缓存回收以及 SWAP 机制,从而进一步导致 I/O 的性能问题等等。

内存泄漏的危害这么大,那我们应该怎么检测这种问题呢?特别是,如果你已经发现了内存泄漏,该如何定位和处理呢。

首先我们使用vmstat,等待一段时间,观察内存的变化情况。

vmstat 3

这里,介绍一个专门用来检测内存泄漏的工具,memleak。memleak 可以跟踪系统或 指定进程的内存分配、释放请求,然后定期输出一个未释放内存和相应调用栈的汇总情况 (默认 5 秒)。

当然,memleak 是 bcc 软件包中的一个工具,我们一开始就装好了,执行
/usr/share/bcc/tools/memleak 就可以运行它。比如,我们运行下面的命令:

# -a 表示显示每个内存分配请求的大小以及地址
# -p 指定案例应用的 PID 号
/usr/share/bcc/tools/memleak -p 23664 -a

总结

应用程序可以访问的用户内存空间,由只读段、数据段、堆、栈以及文件映射段等组成。 其中,堆内存和内存映射,需要应用程序来动态管理内存段,所以我们必须小心处理。不 仅要会用标准库函数 malloc() 来动态分配内存,还要记得在用完内存后,调用库函数 _free() 来 _ 释放它们。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值