这个对象是一个 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
willm 2018-12-13 12:15:47 +08:00 via Android
delete 只是标记内存不再使用,并不一定 memset 为 0。你检测是否回收的方法是有问题的
|
2
cepheus 2018-12-13 12:17:21 +08:00 via Android
o 改成智能指针试试什么?
|
3
willm 2018-12-13 12:22:40 +08:00 via Android
额,看错了。我以为你是直接获取被释放的对象来检测的。
会不会是这个模块重载了 delete 操作符 |
4
zhiqiang OP |
5
wutiantong 2018-12-13 13:39:36 +08:00
boost::circular_buffer 的模版参数是什么?
你 new 的对象是 vector 还是 circular_buffer 还是 circular_buffer 的模版参数? |
6
zhiqiang OP @wutiantong 在扇贝 C++写得多不?
我上面写的有一定简化。 原始对象其实是一个 T,里面有两个成员都是 vector of cirular_buffer of int。 我 new 和 delete 的都是 T。 |
7
GeruzoniAnsasu 2018-12-13 14:26:01 +08:00
我遇到过加载一个 so 内存泄露的问题,dlopen/close 内存是平衡的,但中途调多一个 api 就不平衡了
然后开了 asan 也没发现泄露,查了两天最后发现是 so 会自己 mmap 一块内存自己做内存管理,然后为了保证速度在 deallocate 之后还会预留一块内存以便下次分配加速,这时候 dlclose 它并不会自行 munmap,造成的泄露 我怀疑你遇到的是不是也是 hook 了 allocate/deallocate 造成的问题 |
8
wutiantong 2018-12-13 14:32:44 +08:00
|
9
zhiqiang OP @GeruzoniAnsasu 我多挂载的 so 也是我写的,里面很简单。唯一有问题的,可能在这个 so 也链接 boost circular_buffer 以及我那个类 T 的实现。
现在看来可能是 circular_buffer 的 allocate/deallocate 可能有问题。 |
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
|
11
wutiantong 2018-12-13 14:59:08 +08:00
@arzterk 都已经 delete 了 shrink_to_fit 就不重要了吧。
|
12
wwqgtxx 2018-12-13 15:05:43 +08:00
其实你可以考虑贴出一个可以复现且经过简化的代码放在 gist 上,比这样大家都在猜的效率高得多
|
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++内存管理>>课程 年代久远,已经记不清细节。 |
15
codehz 2018-12-14 00:00:40 +08:00
请务必检查下加载的模块的 ABI 兼容性,比如说编译器,各种库的版本等等,如果有 ABI 兼容问题,也可能导致出现预期之外的行为...
|
16
zhiqiang OP |
17
zhiqiang OP 再补充一下我试验的结果:
我确定 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 之后的内存不释放的情况。可能跟上面发现的特性有关。 |
18
zhiqiang OP 查看了 boost::circular_buffer 的源代码,它用的 allocator 就是 std::vector::allocator,但跟 std::vector 不一样在于,circular_buffer 不会对内存初始化。
内存没用不占用可能是操作系统搞的,虽然分配了地址,但不用就不分配实际物理地址,导致不会实际占用物理内存。 delete 不回收内存的原因还是没搞清楚。 |
19
farseeraliens 2018-12-14 13:07:21 +08:00 via iPhone
heapprofiler 看内存泄漏。asan 是用来看内存非法访问的。
|
20
zhiqiang OP 虽然还没搞清楚确切的原因,但很可能跟分配了大量细碎的内存片段有关。我打算把 circular_buffer 都用内存池管理起来。
|
21
wutiantong 2018-12-14 17:28:59 +08:00
@zhiqiang 就感觉你一直在处理好大一个烂摊子。。。
|
22
zhiqiang OP |