tcmalloc 内存分析

“different,but not less. 不同,但也不差!”

前记

出现内存错误,查问题是一方面,更多的是需要考虑,以后写代码如何不出现内存错误。总结很关键。

  • 《Linux多线程服务端编程使用muduo网络库》这本书说的是RAII技术(后期研究下,做一些实践)。
  • 自己的总结:new 出的内存,不进行类之间的长途传递,若出现这种情况,需要思考下是否真的有必要如此。比如,自己看到的一种比较难受的管理方式:在调用中,new出一个对象A传递指针到另外一个对象B中,并且,最后在对象B析构函数中去释放了A。这种情况,我现在认为的解决办法是传递必要参数到对象B中去new,并且在对象B中的析构中去释放。便于管理。

一、简介

  1. 最近在查程序的内存泄漏问题,是在tcmalloc内存分配的基础上,关于tcmalloc是介绍:主要参见两篇博文:
          (1) 官方文档介绍,主要介绍原理和为什么tcmalloc比glic的快:tcmalloc
          (2) 知乎之前看到一篇分析原理的,楼主添加了很多自己画的图分析,可以当做翻译看:图解tcmalloc
  1. google 出了一套gperftools工具 可以分析cpu占用(profiler.h),分析内存占用(heap-profiler.h),检查内存泄漏(heap-checker.h) ,这里主要讲后面两者的使用
  2. 内存检查的基本原理是:检查运行的代码每个函数中的内存使用情况,生产内存快照文件(即我们需要得到的分析原始数据),内存快速增长的情况下会生成很多的内存快照,后期分析可以前后对比看是什么堆栈的内存分配最多。

二、程序环境配置

  1. tcmalloc环境和库  (http://github.com/gperftools/gperftools) 源码安装
  2. 生成 cpu/内存 采样数据的分析工具:
          (1)pprof工具使用需要安装  graphviz(http://www.graphviz.org)  和 ghostscript(www.ghostscript.com)
 

三、内存分析方式

  1. 情况1:程序本身链接了tcmalloc库,在不重新编译的情况下,使用环境变量进行数据采集     

   #启动程序的方式:
   HEAPCHECK=normal   HEAPPROFILE=prefix  ./test      //需要前台启动程序
     #第一个参数HEAPCHECK表示检查的严格程度    HEAPPROFILE参数表示生产的内存快照
     #默认生成的内存快照文件在/tmp  目录下。

         2. 情况2:在程序中添加接口,以便后期线上直接调用分析

        
使用HeapProFilerStart("prefix")  "prefix"是生成文件的前缀和 HeapProFilerStop 接口  
1.在头文件 <gperftools/heap-profiler.h> 中。 2.可以使用http接口或者telnet 使用方式:程序可以前台,也可以后台,启动之后,发命令或者请求让其执行HeapProFilerStart ,
然后复现程序内存上涨的情况,接着在程序的当前目录可以看到 prefix_heap.
0001.heap (prefix为start传入的前缀),
随着内存上涨,会持续的生很多的内存快照,差不多的时候stop。然后开始使用获得的内存快照分析。

       内存快照的分析方式:

  • 单个快照查看:  使用pprof生成pdf图
执行命令: pprof --pdf  ./test  ./prefix_heap.0001.heap  > 1.pdf  
  • 对比前后快照查看方式:依然使用pprof生成pdf
执行命令:pprof --pdf  --base=prefix_heap.0001.heap   ./test  ./prefix_heap.0002.heap  > 1.pdf 
      
      根据生成的pdf文件查看,主要关注百分比占比很高的堆栈,然后根据这个堆栈去程序中分析申请的内存是否都释放。
      对比生成的数据可以很明显看出内存上涨是哪些函数调用产生的,但是需要根据实际的代码去分析到底有没有内存没有释放。
       

     3.检查片段代码的内存泄漏  :以上两种方式只是用来获取程序内存分配情况的,接下来的方式可以直接检查某个函数的使用到底有没有内存泄漏

        (1)需要在代码中嵌入检查: 使用头文件<gperftools/heap-checker.h> 中的类 HeapLeakChecker 
        (2)添加的代码片段:
  
HeapLeakChecker heap_checker("test_foo");
{
    code that exercises some foo functionality;
    this code should preserve memory allocation state;
}
if (!heap_checker.SameHeap()) assert(NULL == "heap memory leak");
          (3)启动程序: HEAPCHECK=normal  ./test
          (4)输出:
  • 若没有内存泄漏: 
         
 No Leaks found for check "test_foo" 
  • 若存在内存泄漏:
Leak check _main_ detected leaks of 1136 bytes in 2 objects The 2 largest leaks:
Leak of 568 bytes in 1 objects allocated from:
@ 7fa7f4197dd2
 
If the preceding stack traces are not enough to find the leaks, try running THIS shell command:
 
pprof ./bin/exe "/tmp/exe.7539._main_-end.heap" --inuse_objects --lines --heapcheck --edgefraction=1e-10 --nodefraction=1e-10 --pdf
 
If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1 
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false,
it mi Exiting with error code (instead of crashing) because of whole-program memory leaks
 
以上就是内存泄漏的情况下的输出,这个输出不够详细,无法看出泄漏情况,可以参照他的建议执行pprof命令:
pprof ./bin/exe "/tmp/exe.7539._main_-end.heap" --inuse_objects --lines --heapcheck --edgefraction=1e-10 --nodefraction=1e-10 --pdf > 1.pdf
 
查看pdf,同上分析内存分配堆栈来查找内存泄漏的问题。
 

原文地址:https://www.cnblogs.com/panhao/p/10166381.html