C++ delete 对象但内存没被回收? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhiqiang
V2EX    C

C++ delete 对象但内存没被回收?

  •  
  •   zhiqiang 2018-12-13 12:09:49 +08:00 5212 次点击
    这是一个创建于 2564 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这个对象是一个 std::vector<boost::circular_buffer>,我建了几千个这种对象,在 new 时检查内存,大概会增加占用了 10G 内存。

    但随后 delete 这些对象,内存却没有释放。导致程序多来回几次之后占用上白 G 内存然后就挂了。

    不知道有人遇到过同样的案例没?

    系统:ubuntu 16.04, gcc 5.4, boost 1.0.0.68 。

    检查程序实时占的内存我是看 /proc/self/status 的 VmRSS: 那一行。写了一个函数在 new 和 delete 前后实时获取和显示这个值。

    还有一个奇怪的现象,上面占用内存是在程序多调用了一个模块( dlopen 了一个 so 文件)后才会出现。如果没有那个模块,内存增减都是正常的。而这个模块,里面并未操作这些对象。

    第 1 条附言    2018-12-14 17:50:43 +08:00
    问题已解决。手写了一个内存池,作为 boost::circular_buffer 的 allocator。
    22 条回复    2018-12-14 17:48:47 +08:00
    willm
        1
    willm  
       2018-12-13 12:15:47 +08:00 via Android
    delete 只是标记内存不再使用,并不一定 memset 为 0。你检测是否回收的方法是有问题的
    cepheus
        2
    cepheus  
       2018-12-13 12:17:21 +08:00 via Android
    o 改成智能指针试试什么?
    willm
        3
    willm  
       2018-12-13 12:22:40 +08:00 via Android
    额,看错了。我以为你是直接获取被释放的对象来检测的。

    会不会是这个模块重载了 delete 操作符
    zhiqiang
        4
    zhiqiang  
    OP
       2018-12-13 12:26:31 +08:00
    @willm 重载是不可能的,我没写过这么底层的东西,要么就是 boost 里面的实现有重载。

    我怀疑跟 runtime link 有关系。
    wutiantong
        5
    wutiantong  
       2018-12-13 13:39:36 +08:00
    boost::circular_buffer 的模版参数是什么?
    你 new 的对象是 vector 还是 circular_buffer 还是 circular_buffer 的模版参数?
    zhiqiang
        6
    zhiqiang  
    OP
       2018-12-13 14:19:03 +08:00
    @wutiantong 在扇贝 C++写得多不?

    我上面写的有一定简化。

    原始对象其实是一个 T,里面有两个成员都是 vector of cirular_buffer of int。

    我 new 和 delete 的都是 T。
    GeruzoniAnsasu
        7
    GeruzoniAnsasu  
       2018-12-13 14:26:01 +08:00
    我遇到过加载一个 so 内存泄露的问题,dlopen/close 内存是平衡的,但中途调多一个 api 就不平衡了
    然后开了 asan 也没发现泄露,查了两天最后发现是 so 会自己 mmap 一块内存自己做内存管理,然后为了保证速度在 deallocate 之后还会预留一块内存以便下次分配加速,这时候 dlclose 它并不会自行 munmap,造成的泄露


    我怀疑你遇到的是不是也是 hook 了 allocate/deallocate 造成的问题
    wutiantong
        8
    wutiantong  
       2018-12-13 14:32:44 +08:00
    @zhiqiang 好像就我一个人在写 C++...

    我感觉楼上说得有道理,虽然我不懂这块。。。
    zhiqiang
        9
    zhiqiang  
    OP
       2018-12-13 14:35:46 +08:00
    @GeruzoniAnsasu 我多挂载的 so 也是我写的,里面很简单。唯一有问题的,可能在这个 so 也链接 boost circular_buffer 以及我那个类 T 的实现。

    现在看来可能是 circular_buffer 的 allocate/deallocate 可能有问题。
    arzterk
        10
    arzterk  
       2018-12-13 14:42:28 +08:00
    std::vector<T>里面的 capacity 内存是要手动释放的呀,看过 STL 源码都知道的,参考这个 https://en.cppreference.com/w/cpp/container/vector/shrink_to_fit
    wutiantong
        11
    wutiantong  
       2018-12-13 14:59:08 +08:00
    @arzterk 都已经 delete 了 shrink_to_fit 就不重要了吧。
    wwqgtxx
        12
    wwqgtxx  
       2018-12-13 15:05:43 +08:00
    其实你可以考虑贴出一个可以复现且经过简化的代码放在 gist 上,比这样大家都在猜的效率高得多
    zhiqiang
        13
    zhiqiang  
    OP
       2018-12-13 15:29:58 +08:00
    @wwqgtxx 能简化复现的 bug,不会贴到这里麻烦网友们。
    cxytz01
        14
    cxytz01  
       2018-12-13 15:49:45 +08:00
    vector 使用的 allocator 函数有几种:其中一种是不会释放内存给 OS,只会回收给 STL 内存池,这很霸道;一种是直接 malloc,STL 内部不提供内存池;还有其他 alloctator 函数。
    vector 的模板声明是:template<class T, class Allocator = std::allocator<T>> class vector;

    参考上面,选择适合你的 allocator 函数。另外由于编译器版本不同,默认选择的 allocator 函数也不一样,有的版本默认 allocator 函数选择就是不回收内存的 allocator 函数。

    以上知识点参考侯捷大师:<<c++内存管理>>课程

    年代久远,已经记不清细节。
    codehz
        15
    codehz  
       2018-12-14 00:00:40 +08:00
    请务必检查下加载的模块的 ABI 兼容性,比如说编译器,各种库的版本等等,如果有 ABI 兼容问题,也可能导致出现预期之外的行为...
    zhiqiang
        16
    zhiqiang  
    OP
       2018-12-14 08:47:23 +08:00
    @codehz ABI 兼容性应该没问题。那个 so 也是我自己编译的,同一系统同样环境。

    再说能提示下,怎么检查 ABI 兼容性问题吗?
    zhiqiang
        17
    zhiqiang  
    OP
       2018-12-14 08:58:21 +08:00
    再补充一下我试验的结果:

    我确定 boost::circular_buffer 这个东西的内存实现和常规的不太一样,具体表现在分配的空间如果没有实际用上,那么并不会占用太多的内存。有点类似于按需扩容,但我看 boost 的文档,这东西应该是在初始化一次性分配内存的。

    The circular_buffer only allocates memory when created, when the capacity is adjusted explicitly, or as necessary to accommodate resizing or assign operations.

    但我也没试验出 delete 之后的内存不释放的情况。可能跟上面发现的特性有关。
    zhiqiang
        18
    zhiqiang  
    OP
       2018-12-14 09:30:04 +08:00
    查看了 boost::circular_buffer 的源代码,它用的 allocator 就是 std::vector::allocator,但跟 std::vector 不一样在于,circular_buffer 不会对内存初始化。

    内存没用不占用可能是操作系统搞的,虽然分配了地址,但不用就不分配实际物理地址,导致不会实际占用物理内存。

    delete 不回收内存的原因还是没搞清楚。
    farseeraliens
        19
    farseeraliens  
       2018-12-14 13:07:21 +08:00 via iPhone
    heapprofiler 看内存泄漏。asan 是用来看内存非法访问的。
    zhiqiang
        20
    zhiqiang  
    OP
       2018-12-14 14:19:31 +08:00
    虽然还没搞清楚确切的原因,但很可能跟分配了大量细碎的内存片段有关。我打算把 circular_buffer 都用内存池管理起来。
    wutiantong
        21
    wutiantong  
       2018-12-14 17:28:59 +08:00
    @zhiqiang 就感觉你一直在处理好大一个烂摊子。。。
    zhiqiang
        22
    zhiqiang  
    OP
       2018-12-14 17:48:47 +08:00
    @wutiantong 哈哈,可是这烂摊子都是我写的啊。

    感觉项目一大,各种坑会不断冒出来。见得多就好了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2753 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 08:06 PVG 16:06 LAX 00:06 JFK 03:06
    Do have faith in what you're doing.
    ubao msn 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