问题排查¶
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 编译。 - 解决办法:
- 文件名后缀改为
.c
,示例如gcc test.c
。 - 编译选项指定 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 函数之外定义。
- 解决办法:
- 包含 statvfs 所在的头文件,如
#include<sys/statvfs.h>
- 前置声明,如
struct statvfs;
- 包含 statvfs 所在的头文件,如