banner
NEWS LETTER

Linux 开发进阶:内存管理、泄漏排查与常见错误

Scroll down

一、为什么要重视内存

Linux 应用运行时间越长,内存问题越容易暴露。短时间测试正常,不代表长期运行稳定。内存泄漏、越界访问、重复释放、use-after-free 都可能导致崩溃、性能下降或系统被 OOM killer 杀死。

常见内存问题:

  • 内存泄漏。
  • 空指针访问。
  • 数组越界。
  • 重复释放。
  • 释放后继续使用。
  • 栈空间不足。
  • 内存碎片。

二、进程内存布局

一个 Linux 进程大致包含:

1
2
3
4
5
6
text      代码段
data 已初始化全局变量
bss 未初始化全局变量
heap 堆
stack 栈
mmap 动态库、文件映射、匿名映射

查看进程内存映射:

1
cat /proc/<pid>/maps

查看内存统计:

1
cat /proc/<pid>/status

重点字段:

  • VmSize:虚拟内存大小。
  • VmRSS:实际驻留物理内存。
  • VmData:数据段和堆。
  • VmStk:栈。

三、malloc 和 free

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
char *buf = malloc(128);
if (buf == NULL) {
perror("malloc");
return 1;
}

strcpy(buf, "hello memory");
printf("%s\n", buf);

free(buf);
buf = NULL;
return 0;
}

建议:

  • malloc 后检查返回值。
  • 谁申请,谁释放,规则要清楚。
  • free 后把指针置空。
  • 不要返回局部变量地址。
  • 不要越界写入。

四、典型错误

4.1 内存泄漏

1
2
3
4
void leak(void) {
char *buf = malloc(1024);
strcpy(buf, "leak");
}

函数结束后 buf 丢失,内存无法释放。

4.2 use-after-free

1
2
3
char *buf = malloc(128);
free(buf);
printf("%s\n", buf);

释放后继续使用,行为未定义。

4.3 越界写

1
2
char buf[8];
strcpy(buf, "this string is too long");

会破坏栈上其它数据,严重时直接崩溃。

五、AddressSanitizer

编译:

1
gcc main.c -o app -g -fsanitize=address -fno-omit-frame-pointer

运行:

1
./app

AddressSanitizer 可以发现:

  • 越界访问。
  • use-after-free。
  • double free。
  • 部分内存泄漏。

开发阶段建议经常用它跑测试。

六、Valgrind

安装:

1
sudo apt install -y valgrind

检查泄漏:

1
valgrind --leak-check=full ./app

特点:

  • 不需要重新编译。
  • 能输出详细泄漏位置。
  • 运行速度慢。

七、线上内存排查

查看进程内存:

1
ps aux --sort=-%mem | head

查看单进程:

1
cat /proc/<pid>/status

持续观察:

1
watch -n 1 'cat /proc/<pid>/status | grep VmRSS'

如果 VmRSS 持续增长且没有回落,可能存在泄漏。

八、OOM killer

系统内存不足时,内核可能杀死进程。

查看日志:

1
dmesg | grep -i "killed process"

或:

1
journalctl -k | grep -i oom

嵌入式设备内存更小,更容易遇到 OOM。

九、工程建议

  • 明确对象生命周期。
  • 封装申请和释放。
  • 错误分支也要释放资源。
  • 大块内存复用,避免频繁申请释放。
  • 长期运行服务要做压力测试。
  • CI 中加入 AddressSanitizer 测试。

十、总结

内存问题的特点是隐蔽、偶发、破坏性强。开发阶段用 AddressSanitizer,专项排查用 Valgrind,线上观察 /proc、日志和 OOM 记录。

稳定的 Linux 程序,一定要把内存生命周期设计清楚。

其他文章
目录导航 置顶
  1. 1. 一、为什么要重视内存
  2. 2. 二、进程内存布局
  3. 3. 三、malloc 和 free
  4. 4. 四、典型错误
    1. 4.1. 4.1 内存泄漏
    2. 4.2. 4.2 use-after-free
    3. 4.3. 4.3 越界写
  5. 5. 五、AddressSanitizer
  6. 6. 六、Valgrind
  7. 7. 七、线上内存排查
  8. 8. 八、OOM killer
  9. 9. 九、工程建议
  10. 10. 十、总结
请输入关键词进行搜索