zoukankan      html  css  js  c++  java
  • 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,同上分析内存分配堆栈来查找内存泄漏的问题。
     

  • 相关阅读:
    最长上升子序列(矩形嵌套)
    中国剩余定理模板poj1006
    POJ 2891 扩展欧几里德
    2015多校联赛第三场(部分题解)
    树链剖分
    深度理解链式前向星
    POJ 1228 Grandpa's Estate(凸包)
    旋转卡壳(一)
    最小圆覆盖 hdu 3007
    半平面求交 模板
  • 原文地址:https://www.cnblogs.com/panhao/p/10166381.html
Copyright © 2011-2022 走看看