Core_analyzer工具提供了以下功能:
文章插图
Core_analyzer用户界面
[0] 打印core文件的基本信息,包括各个线程的信息,和内存段的信息等 。
[1] 水平搜索对象的引用
[2] 垂直搜索对象的引用链,直到找到符号表中有调试信息的对象 。
[3] 打印线程共享对象
[4] 打印给定地址段的内容
[5] 通过地址查询所属chunk
[6] 打印所给的地址周围的页(意义不明)
[7] 打印整个堆的结构 。该结构能够与ptmalloc的结构相对应
[8]、[9]都是打印前N大的chunk,[9]还顺便打印出引用链
[10] 根据它的名字为内存泄漏检测,但实际使用发现不仅耗时而且不正确
[11] 退出
原本的core_analyzer功能就上述这些,但是在实际使用过程中发现它对于线程较多(大于32)的进程支持并不好,所以在对其进行了改造后,又顺便添加了两个功能:
[12] 以chunk大小分类,并按照占用总大小排序 。
[13] 打印出所有的chunk 。由于结果可能较大,所以打印在out.txt文件中 。
项目原地址:https://github.com/yanqi27/core_analyzer.git
改动过后的工具开源在igit上:http://igit.58corp.com/jichenxuan/core_analyzer_fixed.git
3.分析方法
首先我们需要生成一个core文件 。使用gcore命令可以不杀死进程同时生成core文件 。执行命令:
gcore 12763
但是在生成core文件的过程中进程是暂停的,而且会将打开的mmap文件全部读取到内存中,因为它本身是通过gdb attach pid&& gcore实现的,所以对线上的服务需要酌情使用 。现在我们拿到了一个core.pid文件 。执行
core_analyzerrealtime_searcher core.12763
第一个参数为可执行程序 。之后会看到core_analyzer询问core文件的main_arena和mp_地址 。通过gdb命令print &main_arena 和 print &mp_可以拿到这两值
文章插图
使用gdb打印main_arena和mp_的地址
如果安装了glibc对应版本的调试信息,就可以看出这两个变量分别为malloc_state和malloc_par,ptmalloc使用这两个结构体管理分配区(arena),其中每一个分配区都是malloc_state的一个实例,而malloc_par则是参数管理,为静态成员,全局有唯一的malloc_par实例 。变量main_arena即为主分配区实例,ptmalloc中所有的分配区组织成一个环形链表的结构,如下图(图自http://core- analyzer.sourceforge.net/index_files/Page335.html),有了主分配区就可以遍历这个链表,拿到所有的分配区信息 。
文章插图
Ptmalloc结构
在当前环境下这两个结构体分别如下图所示,有兴趣可以对照ptmalloc的结构了解各个成员的含义这里不多介绍 。不同版本的ptmalloc实现在这两个结构体的实现上有些许差异,但都是大同小异 。
文章插图
Ptmalloc数据结构源码
将上述两个结构体的地址填入core_analyzer中,稍等一下加载过程,便可以看到它的功能界面 。首先可以使用Print General Core Information可以看到每个线程的状态,收到的信号等,以及整个进程的内存地址从低到高的布局 。可以对进程状态有个大致的了解 。
文章插图
各个线程状态
文章插图
进程内存布局
执行Heap Walk便可将ptmalloc层的完整结构打印出来 。由于打印内容较多,我们拆开来看 。
文章插图
打印ptmalloc堆结构
前边几行打印出记录在malloc_par结构中的内容,也就是一些参数 。我们重点关注一下n_mmaps和mmaped_mem这两个值,就是说由ptmalloc申请的mmap chunk一共有70个,占用总空间为3213393920字节,记住这个值之后会分析到 。
下边从Main arena开始就是所有的分配区信息 。
Main arena:主分配区信息 。主分配区从heap段分配空间,调用brk/sbrk增长,地址连续,所以只有一个堆块 。
Dynamic arena:非主分配区信息 。从mmap段开始分配空间(注意这里的mmap含义为进程地址空间的mmap段,有别与前文中的mmap调用,后边还会有,注意区分),其下的每一行表示一个子堆(struct heap_info实例),每个子堆大小上限为64M,用完后需要调用mmap申请新的子堆,子堆以链表结构链在头节点后 。
推荐阅读
- linux日志关键字检索&处理
- linux中多种查看系统时间的命令
- 本地Docker Jenkins构建dotcore web应用到Linux服务器 Docker上
- 在 Linux 终端快速检测网站是否宕机的 6 个方法
- linux run level 为何物
- SQLite使用内存数据库
- Linux下如何使用crontab来定时执行脚本任务?
- Linux的图形用户界面-你会选择哪个?
- Linux的Cache和Buffer理解
- 不知道这十项Linux常识,别说自己是运维工程师