7

据我了解,内存池是一个块,或者是运行前在堆栈上分配的多个内存块。
相比之下,据我了解,动态内存是从操作系统请求的,然后在运行时分配到堆上。

// 编辑 //

  • 内存池显然不一定在堆栈上分配,即。内存池可以与动态内存一起使用。
  • 根据这个问题的答案,非动态内存显然也不一定在堆栈上分配。
  • 因此,尽管答案仍然相关,但“动态与静态内存”“内存池”的主题并不真正相关。

据我所知,内存池的目的是提供对 RAM 的手动管理,其中内存必须由程序员跟踪和重用。

这在理论上对性能是有利的,原因有很多:

  1. 随着时间的推移,动态内存变得碎片化
  2. CPU 可以比动态块更快地解析内存的静态块
  3. 当程序员可以控制内存时,他们可以根据具体的程序选择在最好的时候释放和重建数据。

4、多线程时,分离池允许不同线程独立运行,无需等待共享堆(Davislor)

我对内存池的理解正确吗?如果是这样,为什么似乎不经常使用内存池?

4

3 回答 3

8

这个问题似乎与XY 问题过早优化有关。

您应该专注于编写清晰的代码,然后在必要时使用分析器执行优化。

我对内存池的理解正确吗?

不完全的。

...在堆栈上...

...在堆上...

存储持续时间与池的概念是正交的;可以将池分配为具有四种存储持续时间中的任何一种(它们是:静态、线程、自动和动态存储持续时间)。

C++ 标准不要求这些中的任何一个进入堆栈;将它们全部视为进入同一个地方可能会很有用……毕竟,它们(通常)都进入硅芯片

... 分配 ... 在运行前 ...

重要的是多个对象的分配发生在这些对象第一次使用之前(或至少不那么频繁);这样就不必分别分配每个对象。我认为这就是您所说的“运行前”。在选择分配大小时,越接近在任何给定时间所需的对象总数,过度分配造成的浪费就越少,过度调整大小造成的浪费也就越少。

但是,如果您的操作系统不是史前的,那么池的优势将很快消失。如果您在进行优化之前和之后使用分析器,您可能会看到这一点!

  1. 随着时间的推移,动态内存变得碎片化

对于 Windows 1.0 等幼稚操作系统来说,这可能是正确的。但是,在当今时代,具有分配存储持续时间的对象通常存储在虚拟内存中,虚拟内存会定期写入磁盘并从磁盘读取(这称为分页)。因此,碎片化的内存可以进行碎片整理,更常用的对象、函数和方法甚至可能最终合并到公共页面中。

也就是说,分页为您形成了一个隐式(和缓存预测)!

CPU 可以比动态块更快地解析内存的静态块

虽然分配有静态存储持续时间的对象通常位于堆栈上,但这不是 C++ 标准的强制要求。完全有可能存在 C++ 实现,而是在堆上分配静态内存块。

对动态对象的缓存命中将与对静态对象的缓存命中一样快。碰巧堆栈通常保存在缓存中。你应该试着在没有堆栈的情况下编程一段时间,你可能会发现缓存有更多的堆空间!

在优化之前,您应该始终使用分析器来测量最重要的瓶颈!然后您应该执行优化,然后再次运行分析器以确保优化成功!

这不是一个独立于机器的过程!您需要优化每个实现一种实现的优化可能是另一种实现的悲观

如果是这样,为什么似乎不经常使用内存池?

上面描述的虚拟内存抽象与使用缓存分析器消除猜测相结合,实际上消除了在所有情况下的用处,除了最不知情(即使用分析器)场景。

于 2017-05-30T06:20:35.457 回答
2

自定义分配器可以提高性能,因为默认分配器针对特定用例进行了优化,这种情况很少分配大块内存。

但是,例如在模拟器或游戏中,您可能在一帧中发生很多事情,非常频繁地分配和释放内存。在这种情况下,默认分配器不是很好。

一个简单的解决方案可以是为一帧期间发生的所有一次性内容分配一块内存。这块内存可以一遍又一遍地覆盖,删除可以推迟到以后。例如:游戏关卡结束或其他。

于 2017-05-30T05:26:26.040 回答
2

内存池用于实现自定义分配器。

一种常用的是线性分配器。它只保留一个分隔已分配/空闲内存的指针。使用它进行分配只是将指针增加 N 个请求的字节,并返回它的先前值。释放是通过将指针重置为池的开头来完成的。

于 2017-05-30T06:51:42.037 回答