如何处理大型 C++程序的内存泄露问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
matthewgao
V2EX    C

如何处理大型 C++程序的内存泄露问题

  •  
  •   matthewgao 2015-07-29 19:58:51 +08:00 2684 次点击
    这是一个创建于 3727 天前的主题,其中的信息可能已经有所发展或是发生改变。

    程序在一个月的运行中不断吃内存,一个月吃掉了32G的内存,但是线上系统还不能停,不能改配置。。。。 有什么好办法排除内存泄露的问题么?

    第 1 条附言    2015-07-29 22:03:27 +08:00
    重新看一遍代码是最后的办法,但是很困难,代码量太大
    31 条回复    2016-02-20 23:49:58 +08:00
    linxy
        1
    linxy  
       2015-07-29 20:01:45 +08:00
    换go
    matthewgao
        2
    matthewgao  
    OP
       2015-07-29 20:03:35 +08:00
    @linxy 不现实。。。
    acros
        3
    acros  
       2015-07-29 20:11:43 +08:00
    占个座位等解答。
    这种环境下,是不是只能靠内存dump分析了?
    fo2w
        4
    fo2w  
       2015-07-29 20:15:32 +08:00
    看描述我完全不知道你是要解决问题还是排查问题
    不停机不能改配置要解决问题那无解, 或者我太废柴暂时没想到办法
    要查问题这种情况下钩子就好了

    但是...我还是建议好好review一遍代码...
    这种泄漏量肉眼我真不信看不出来
    sinxccc
        5
    sinxccc  
       2015-07-29 20:16:13 +08:00
    我们常用的做法是首先复制一个尽可能跟在线系统一样的环境,然后如果性能说得过去的话用 valgrind 跑可疑进程,对性能要求高的话,加上自己包装过的 new/delete/malloc/free 然后跑一段时间看输出的统计。

    分离出最可疑的地方之后再按照这个特征走查代码。
    lijianying10
        6
    lijianying10  
       2015-07-29 20:20:45 +08:00   1
    不知道是何种业务,
    1. 取一份程序拷贝准备复现问题
    2. 两个方面来确定问题的来源
    1. 用更高的业务访问频率(业务参数)来模拟在线程序的情况,让问题显现更清楚
    2. 满足上面一条之后,(如果是巨大循环的算法)每次注释掉一个模块,来排查问题。找到是那个大模块之后,再从大模块入手使用同样方法,直到找到泄露点。
    1. 尽量避免注释掉依赖模块。从底层开始。
    2. 模块的划分粒度大小很重要,影响排查速度
    3. 如果是由独立业务堆砌出来的大型程序,要从业务划分来找到一个或者多个业务发生泄露,然后使用上面的方法
    4. 如果十分确定使用上面两条找不到。最后一招CodeReview。
    5. 找到来源之后修复一下,做项目回归测试。

    希望此流程能帮到楼主。这也是我在做计算程序的时候排查泄露时候的方法。
    ch3n2k
        7
    ch3n2k  
       2015-07-29 20:32:34 +08:00
    加大swap,让它泄漏去。话说什么程序不能停机啊?要改架构啊
    typcn
        8
    typcn  
       2015-07-29 20:42:31 +08:00
    @ch3n2k 内存泄露只是丢失访问途径,而且还非常容易造成程序的崩溃,仅仅占内存的话,那叫内存申请不合理,没有释放

    还是用 valgrind 跑吧,手找累死人
    zhouc
        9
    zhouc  
       2015-07-29 22:03:47 +08:00
    你们的程序是server程序,不能load balance traffic?
    jedihy
        10
    jedihy  
       2015-07-29 22:16:44 +08:00 via iPhone
    对,valgrind,差不多就这些办法。一般单元测试的时候就要按模块找出内存泄露,不然耦合到一起很难找了。
    lsmgeb89
        11
    lsmgeb89  
       2015-07-29 22:25:29 +08:00
    大型的 C/C++ 程序,一开始开始就要考虑到内存管理模块啊,团队要制定好内存使用的规则,这样出现内存泄漏就可以定位到那个 instance 和代码位置。

    PS:用 Valgrind 跑很慢的,而且不一定能够定位的。
    xylophone21
        12
    xylophone21  
       2015-07-29 22:38:08 +08:00   1
    #define new(x) mynew(__FILE__,__LINE__,x);
    signifox
        13
    signifox  
       2015-07-29 23:32:04 +08:00
    gcc4.8以上版本用[AddressSanitizer]{https://code.google.com/p/address-sanitizer/wiki/AddressSanitizer},
    低版本的用[efence]{https://directory.fsf.org/wiki/Electric_Fence}

    检查C++内存泄露的神器。
    alphonsez
        14
    alphonsez  
       2015-07-30 00:07:20 +08:00
    建议改成能重启的。老不能重启总是个麻烦,总不见得永远不部署吧?如果能重启就好办了,每天重启一次呗。
    akira
        15
    akira  
       2015-07-30 00:59:37 +08:00
    如果有完善的日志的话,可以试试从日志里分析出业务量变化和内存增加变化的关系。定位到业务的话 就比较好做代码review了
    dndx
        16
    dndx  
       2015-07-30 01:07:21 +08:00 via iPhone
    用智能指针。
    JamesRuan
        17
    JamesRuan  
       2015-07-30 02:01:11 +08:00
    上Erlang/OTP
    vietor
        18
    vietor  
       2015-07-30 08:16:50 +08:00 via Android
    所有内存分配回收代码都过一遍, 尤其用指针封装的地方(智能指针,共享指针),许多人没理解就乱用,用错。我之前就将所有智能指针转成自写封装类,解决内存泄漏
    nightv2
        19
    nightv2  
       2015-07-30 09:43:08 +08:00
    重启啊,至少能改善问题,然后排查是那个模块
    qyz0123321
        20
    qyz0123321  
       2015-07-30 09:50:33 +08:00
    智能指针是王道
    eliteYang
        21
    eliteYang  
       2015-07-30 10:13:16 +08:00
    强烈推荐intel vtunes分析,或者全局用智能指针,或者全局排查指针申请和释放的地方,看看有没有因为什么情况导致申请完后一些条件不满足,没有走到释放
    hitmanx
        22
    hitmanx  
       2015-07-30 10:30:42 +08:00
    生产环境不能停机的话,可以开发环境重新跑一次,并打开valgrind\address sanitizer之类的工具在运行时检测一下内存泄露。如果这也不行的话,可以上一些静态代码分析工具看看,比如coverity之类的
    acgeo
        23
    acgeo  
       2015-07-30 11:25:18 +08:00
    楼上各位说得都是扯犊子的~~

    这种情况,吃内存是无法避免的~

    写个shell脚本 定时执行~ 这样每次执行完毕,进程结束会自动释放掉内存.
    pp3182429
        24
    pp3182429  
       2015-07-30 13:29:40 +08:00
    以前每次都是check所有分配内存的地方,是不是释放了…找所有的new和malloc==#。。
    acgeo
        25
    acgeo  
       2015-07-30 15:54:28 +08:00
    楼上各位说得都是扯犊子的~~

    这种情况,吃内存是无法避免的~

    写个shell脚本 定时执行~ 这样每次执行完毕,进程结束会自动释放掉内存.
    linux40
        26
    linux40  
       2015-07-30 16:27:50 +08:00
    为什么不用标准库里的模板?虽然我不是很懂工程这种东西。。。
    magicyu1986
        27
    magicyu1986  
       2015-07-30 17:07:28 +08:00
    上测试环境一块一块的排查,真没有其他好办法。

    最好还是上一套半自动内存管理的东西:智能指针,循环引用检查啥的。
    acgeo
        28
    acgeo  
       2015-07-30 19:37:33 +08:00
    楼上各位说得都是扯犊子的~~

    这种情况,吃内存是无法避免的~

    写个shell脚本 定时执行~ 这样每次执行完毕,进程结束会自动释放掉内存.!
    matthewgao
        29
    matthewgao  
    OP
       2015-07-30 22:32:40 +08:00
    程序比较老,写的时候没有一个好用的智能指针,然后是一个大牛自己写的智能指针,诡异的就在于各个版本从来没出过问题,就这一台机器,同版本的其他机器也没出过问题,这个机器也没什么特别特殊的配置,所以很诡异
    我现在怀疑是STL,有些容器不会自动shrink的问题。
    matthewgao
        30
    matthewgao  
    OP
       2015-07-30 22:33:10 +08:00
    总之还是谢谢各位,我去试试AddressSanitizer,看看有什么效果不
    matthewgao
        31
    matthewgao  
    OP
       2016-02-20 23:49:58 +08:00
    我来做个了结,最终还是靠 review 代码, 找到了泄露的地方, 10w 行。。。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2687 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 07:23 PVG 15:23 LAX 00:23 JFK 03:23
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86