C++动态内存管理问题求解

2022-06-29 11:30:17 +08:00
 ligiggy

项目上需要处理若干组,每组 500M 左右的数据,数据组成是大概可以理解为 3 个 std::vector<float>,一个 std::vector<structA>( structA 为自定义结构体),每处理一组数据就需要释放掉。

数据处理大概包括:插值,平移等。

由于载入内存比较大,导致处理的时间越来越长,内存越来越碎片化。

找了几个内存池的解决方案,好像不是很好解决我的问题。比如 boost::pool ,std::allocator ,使用起来都比较麻烦,比如 boost ,很多释放都是静态的,allocator 的话,基本上需要重新造轮子。后面发现 c++17 添加了 pmr::monotonic buffer resource ,尝试 debug 几次之后,发现在现在的机器上一次只能分配 100M 的内存,200M 和 500M ,都会在运行的时候崩溃掉,应该是没有那么多的连续内存了,想问下大佬们,有什么推荐的解决方案(轮子)吗?

我期望中的解决方案其实与 pmr 的预期类似,就是我申请一块足够大的连续内存,让这块内存分配数据的存储空间,处理完后,直接将整块内存释放掉即可。如果没有联系的内存,也可以分配成几个 100M ,几个 50M ,几个 20M 这样子的,也会比完全碎片化的要快。

4189 次点击
所在节点    C++
43 条回复
FrankHB
2022-07-01 03:07:58 +08:00
@ipwx 你说的思路粒度太大。从 OP 的描述看,我不认为这没被考虑过,倒是一些坑没被说,所以提了一下。
我说的其实也不十分细(而且不怎么对口,跟 mimalloc 的目标领域倒是强相关),不过既然 mimalloc 都被 OP 认为看上去有帮助了,所以也没多计较这个。
要说优化,是十分有讲究的,跟具体负载关系很大,坑也各自不一样,所以没有具体的代码也没法说得很细。光是怎么踢出去的策略,实际表现的上下限距离就挺大。如果非得不限定场景,那么只能说 pmr 里的 pool resource 基本算是 C++能用的各种意义上(除了具体实现的坑)最高效的了。
(这里还是排除复制 allocator 的问题。理论上更高效的是用 keyed static variable 之类比 thread_local 更扩展的机制避免要求有状态 allocator 的复制,但这个不是得改核心语言中很基本的规则就得魔改 ABI ,C++范围内就算了。)
至于碎片,不是用不用 allocator 的关系,是只要算法不能确保完全静态确定分配,这总是会存在,无非是怎么把问题变小。mmap 之类用好了可能解决问题,但太不具体( OP 不给代码也没法具体),而且实际上不太容易用好,不仔细优化极可能有空间利用进一步下降的代价,照样可以加剧原始问题。

@mingl0280 OP 既然都用上 pmr 了,表明实际代码很可能难以套用你测试程序的方式使用,“简单方便”是很可疑的。
这种情况下,只要大的方向(最底层用什么分配)正确,随便一个输入数据和实际生成优化代码的不确定抖动都可能让这里的差距化为虚无,缺乏显著性。
考虑到 OP 似乎只用 trivial copyable 类型的数据,你的方式不是没实际优势——对编译器优化的不确定性小,编译开销也小。但这也就是确保能改得过来,而不是一定更好。
FrankHB
2022-07-01 03:15:57 +08:00
我顺便提一下,pmr 用起来可能有个常识性的坑 OP 不知道有没有绕过去了——copy 容器时 pmr polymorphic_allocate 不会 propagate ,因为 pmr::polymorphic_allocator select_on_container_copy_construction 会返回默认初始化的 allocator 。
如果没注意,复制(包括传参和返回)容器对象时没有显式使用 allocator 或者 uses_allocator allocation ,退回到默认 new_delete_resource ,不但基本是纯粹的性能回归 bug ,还可能会在 swap 等操作中凭空多出 UB 。
一旦已经注意到这个问题并正确实现,前面一些回复的手动加 buffer 的实现改起来差距就大了。
ligiggy
2022-07-01 09:10:29 +08:00
@FrankHB 不给代码,是因为这部分内容太过复杂了(处理比较多),也涉及到几个跟同事的核心算法(很难避开),很难去给出 代码样例。

针对 @mingl0280 这位老哥的分析也很好,我真的很能明白这位老哥的意思,但是我的算法代码实在是不能这样写,也不知道怎么跟他解释清楚,感谢你的解释。

当然,也因为我没给出实例代码,可能导致诸如我忽视了某些个细节的处理,导致内存碎片。也有可能因为魔改了很多三方库导致的,比如 opencv 和 eigen 。可能我的关键问题不是用动态内存管理的库吧,仔细琢磨代码细节,找出漏洞可能才是解决问题的办法。

总而严重,感谢你的耐心回复和解释,我继续加油了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/862885

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX