使用显式大小释放内存

6
我正在寻找主流操作系统中类似于malloc/free的API,允许我在分配和释放内存时指定显式大小。我希望通过这样做,运行时可以在程序中已知分配大小的情况下减少内存占用。例如,在Windows中,我只发现了free()_aligned_free()_freea(),它们都不接受第二个表示大小的参数。

5
我的希望是通过这样做,使运行时在记账方面使用的内存减少,而让你的程序使用内存来跟踪大小? - Blaze
1
准确地说,通常这些信息已经是必要的/可用的。 - B_old
3
@Blaze 这其实是一个有效的问题,因为程序通常会跟踪对象的大小。 - user7860670
3
关于这个问题本身,没有这样的API,您需要编写自定义分配器。 - user7860670
3
在一个普通的 C++ 程序中,分配大小几乎总是已知的。例如,std::vector 的大小是已知的,任何多态对象的大小也是已知的,任何具有非平凡析构函数的对象数组的大小也是已知的。可惜的是,我们大部分时间都会重复存储大小信息(或者我们不会将这些信息提供给分配器,以便它更快)。 - geza
显示剩余17条评论
3个回答

3
我正在寻找主流操作系统中类似于malloc/free的API,允许我在分配和释放时指定明确的大小。
据我所知,没有。
希望通过这样做的目的是,当程序中已有分配的大小时,运行时可能会少花费一些内存来进行簿记。
这个想法肯定可行,但有几个缺点:
- 你必须在调用者跟踪分配大小的对象和分配器仍需要自己记录大小之间分配区域。 这增加了复杂性,还可能导致内存碎片。 - 你必须恰好分配程序请求的大小。 也就是说,通常的分配器可以决定为64字节的请求返回96字节的块,因为它刚被释放,因此在高速缓存中很热,而且分割和重新合并小于64字节的块不被认为是值得的。 你的分配器通常不能这样做(它限于向上舍入到下一个对齐的块大小)。
当然,有许多专门的分配器可以显式地管理这些权衡。
当通用分配器不适合您的分配模式时,使用或编写这些是完全正常的事情。但是,它们通常不由语言或操作系统提供,因为它们不是通用的。它们由库(或您自己)提供。
例如:
- 您需要频繁分配和释放具有先前已知固定大小的对象。 为它们编写对象池分配器。它不需要跟踪分配大小,因为它总是相同的(通常是一个模板参数)。在您的代码中也不需要显式跟踪它,因为它隐含在类型中。 - 带有相同生命周期的大量简单对象的可变大小分配(例如,许多字符缓冲区)。 为其编写arena分配器。它不需要跟踪个别分配大小,因为您重置整个分配器而不是释放和重新分配单个对象。您永远不会明确删除分配的对象,因为它们本来就是平凡的。
注:如果选择使用new/delete重载集成分配器(并认为显式大小参数会带来好处),则可以使用Maxim指出的那些重载集,但有以下警告:
当删除不完全类型的对象和非类和平庸析构类类型的数组时,如果提供了用户定义的替换,则调用[显式大小重载],而不是调用[默认重载],但未规定应调用哪个。

0

如果您正在寻找更快的malloc和free,那么现在有一个新的(2019年2月13日)替代品可供使用,适用于已经支持硬件内存管理单元MMU的系统。大多数计算机都支持,而大多数微控制器则不支持。

有一篇论文和一项研究表明,它可以将Firefox的内存减少16%,Redis的内存减少39%。

它被称为Mesh。Mesh动态内存分配


0

operator delete家族确实接受大小参数。请参见operator deleteoperator delete[]

void operator delete  (void* ptr, std::size_t sz) noexcept;
void operator delete[](void* ptr, std::size_t sz) noexcept;
void operator delete  (void* ptr, std::size_t sz, std::align_val_t al) noexcept;
void operator delete[](void* ptr, std::size_t sz, std::align_val_t al) noexcept;

Called instead of void operator delete(void* ptr) noexcept and void operator delete[](void* ptr) noexcept; if a user-defined replacement is provided.

通过编译器为您提供大小的好处。


您引用的参考资料还说:“内存分配器可以使用给定的大小来更高效地工作。标准库实现与(1-2)相同。”那么,是否仍然需要编写自定义分配器呢? - B_old
@B_old 您需要替换全局的 new 和这些版本的 delete,以使用您自定义的分配器,在释放时接受大小。 - Maxim Egorushkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接