跳转至

问题排查

1 生产问题排查

1.1 stack 资源限制导致进制启动失败

  • 问题原因:stack size 设置成 unlimited 后导致启动失败,设置一个准确值启动成功。具体原因未分析出。
  • 分析过程:
  • 在生产环境上启动脚本,显示执行失败,查看日志,没有任何信息,打开 debug 日志,依然没有有效日志产生;查看 core dump 目录下是否产生 core dump 文件,没有。
  • 直接启动进程,进程并没有返回任信息。
  • gdb 调试启动进程,由于编译器的优化,效果不理想,进入子进程无法继续跟踪。
  • 查看系统日志 /var/log/messages,grep 过滤进程 A 相关日志,发现有进程异常退出日志,必然会产生 core dump 文件,于是使用 ulimit -a 检查 core dump 文件大小等于 0,再查看 /proc/sys/kernel/core_pattern,重新设置 core dump 文件生成位置 echo "/tmp/core-%e-%p-%t" > /proc/sys/kernel/core_pattern
  • 重新启动进程 A,查看 core dump 文件,gdb 查看,发现 core 位置是在对一个栈内存数组 memset 时出现问题。按往常经验(栈内存访问出错很少见),怀疑是其它地方导致的问题。多次启动进程 A,获取多个 core dump 文件,查看,依然是 core 在 memset 栈内存数组上。
  • 开始怀疑是栈大小问题,通过 ulimit -a 查看最大栈大小,结果是 unlimited,所以排除了栈的问题。
  • 询问其它同事,有没有修改过系统环境,反馈修改过 stack 大小为 unlimited,原先是 512000。怀疑还是和这个 stack 大小有关,查阅资料,发现有些人遇到过设置 stack size =unlimited 后,进程异常问题。
  • 使用 ulimit -s 512000 恢复 stack size 后,再次启动进程 A,进程启动成功。
  • 询问同事,是否可以将此参数恢复,得到的答案是否到的,所以,没有去修改 /etc/security/limits.conf 文件使永久生效;采用启动进程 A 前,先 ulimit -s 512000,再启动进程方式。
  • 问题解决:在启动进程前,使用 ulimit -s 131072 设置 stack 大小为一个具体值,再启动进程。

1.2 使用 perf 工具排查 cpu 异常

使用 perf -p pid -g -F99 命令采样某个进程堆栈信息。通过热点函数占用 cpu 时间来确定异常代码位置。

1.3 使用 pstack 分析进程卡在哪个问题

当进程卡死时,使用 pstack 命令打印堆栈信息,分析堆栈中异常部分,通常和锁相关,带有 wait 或 lock 关键字的尤其关注。

2 开发问题排查

2.1 malloc、free 后进程内存没有降低?

  • 问题原因:频繁的使用 malloc 分配小内存(默认 128k 由 brk 分配的),再 free,某种情况下,导致堆内碎片过多,堆顶一直往后移。
  • 解决办法:
    • 使用 malloc_trim (0) 强制回收堆顶内存(测试显示对内碎片也被回收,这个原因不清楚)。
    • 使用内存池管理。 参考资料

2.2 使用了线程不安全函数,导致偶发问题

2.3 编译 attr 源码包解决 getfattr 乱码问题

  • 问题原因:
  • 分析过程:

2.4 memset 含 stl 类型数据导致 core

  • 问题原因:stl 类型可能内部有指针,memset 把这些指针赋值为 0 了,导致访问数据失败。
  • 分析过程:

2.5 使用 valgrind Massif 排查内存占用异常

可选的关注内存峰值,重点关注内存占比高的那部分。

2.6 使用 valgrind Memcheck 检测内存泄漏

跑一遍 Memcheck 后,重点关注 definitely lost 部分。

3 编译问题

3.1 使用 gcc 而不是 g++ 编译,依然按 c++ 编译

  • 问题原因:原编译命令如 gcc test.c ;指定 gcc,会通过文件名后缀来采用何种编译器。而测试编译的文件名后缀是 .cc 这就导致没有按预期的 c 编译。
  • 解决办法:
    1. 文件名后缀改为 .c,示例如 gcc test.c
    2. 编译选项指定 c 编译,选项为 -xc,示例如 gcc -xc test.cc

3.2 ‘struct statvfs’在形参表内部声明

  • 错误输出
test.h:52:49: 警告:‘struct statvfs’在形参表内部声明 [默认启用]
 int adapter_statfs(const char *pathname, struct statvfs *stbuf, NCDFS *sp);

ncdfs.h:52:49: 警告:它的作用域仅限于此定义或声明,这可能并不是您想要的 [默认启用]
  • 问题原因:statvfs 没有在 adapter_statfs 函数之外定义。
  • 解决办法:
    1. 包含 statvfs 所在的头文件,如 #include<sys/statvfs.h>
    2. 前置声明,如 struct statvfs;