了解内存池
Understanding Memory Pools
根据我的理解,内存池是一个块,或者在运行时间之前在堆栈上分配的多个内存块。
相比之下,据我了解,动态内存是从操作系统请求的,然后在 运行 时间内在堆上分配。
// 编辑 //
- 内存池显然不一定分配在堆栈上,即。内存池可以与动态内存一起使用。
- 非动态内存显然也不一定在堆栈上分配,根据这个问题的答案。
- 'dynamic vs. static memory' 和 'memory pools' 的主题因此并不真正相关,尽管答案仍然相关。
据我所知,内存池的目的是提供 RAM 的手动管理,其中内存必须由程序员跟踪和重用。
这在理论上有利于性能,原因有很多:
- 随着时间的推移,动态内存变得碎片化
- CPU 可以比动态块更快地解析静态内存块
- 当程序员可以控制内存时,他们可以根据特定程序选择在最佳时机释放和重建数据。
4.多线程时,separate pools允许单独的线程独立运行,无需等待共享堆(Davislor)
我对内存池的理解是否正确?如果是这样,为什么内存池似乎不经常使用?
自定义分配器可以提高性能,因为默认分配器针对特定用例进行了优化,这种用例很少分配大块内存。
但是,例如在模拟器或游戏中,您可能会在一帧中发生很多事情,非常频繁地分配和释放内存。在这种情况下,默认分配器不是很好。
一个简单的解决方案是为一帧期间发生的所有一次性事件分配一块内存。这块内存可以一遍又一遍地覆盖,删除可以推迟到以后。例如:游戏关卡结束或其他。
似乎这个问题被 XY problem and premature optimisation 所阻碍。
您应该专注于编写易读代码,然后使用分析器执行优化如有必要。
Is my understanding of memory pools correct?
不完全是。
... on the stack ...
... on the heap ...
存储持续时间与池的概念正交; 池可以分配为具有四种存储持续时间任何(它们是:静态、线程、自动和动态存储持续时间)。
C++ 标准不要求 任何 进入 堆栈 或 堆;将它们全部视为进入同一个地方可能会很有用...毕竟,它们都(通常)进入硅片!
... allocate ... before runtime ...
重要的是多个对象的分配发生在之前(或至少少于)这些对象首次被使用;这样就不必单独分配每个对象。我假设这就是您所说的“在 运行time 之前”的意思。选择分配大小时,在任何给定时间越接近所需的对象总数,过度分配造成的浪费和过度调整大小造成的浪费就越少。
但是,如果您的 OS 不是史前的,游泳池的优势将很快消失。如果您在 之前和之后 进行优化,您可能会看到这一点!
- Dynamic memory becomes fragmented over time
这对于 Windows 1.0 等天真的操作系统可能是正确的。然而,在当今时代,具有分配存储持续时间的对象通常存储在 虚拟内存 中,它会定期写入并从磁盘读回(这称为 分页)。因此,可以对碎片化的内存进行碎片整理,更常用的对象、函数和方法甚至可能最终合并到公共 页.
即paging为你形成一个隐含的pool(以及cache prediction) !
The CPU can parse static blocks of memory faster than dynamic blocks
虽然分配了静态存储持续时间的对象通常位于堆栈上,但 C++ 标准并未强制要求这样做。完全有可能存在 C++ 实现,其中 静态内存块 被分配 在堆 上。
动态对象的缓存命中与静态对象的缓存命中一样快。 堆栈 通常保存在缓存中;你应该尝试没有堆栈的编程一段时间,你可能会发现缓存有更多空间用于堆!
在优化之前,您应该始终使用分析器来衡量最重要的瓶颈!然后您应该执行优化,然后运行再次分析器以确保优化成功!
这不是一个独立于机器的进程!您需要优化 per-implementation! 对一个实现的优化可能对另一个实现悲观。
If so, why does it seem like memory pools are not used very often?
上面描述的虚拟内存抽象,结合使用缓存分析器消除猜测实际上消除了池在所有方面的用处但信息最少的(即使用分析器)场景。
内存池用于实现自定义分配器。
一种常用的是线性分配器。它只保留一个指针分隔 allocated/free 内存。用它分配只是将指针递增所请求的 N 个字节,然后返回它之前的值。释放是通过将指针重置为池的开始来完成的。
根据我的理解,内存池是一个块,或者在运行时间之前在堆栈上分配的多个内存块。
相比之下,据我了解,动态内存是从操作系统请求的,然后在 运行 时间内在堆上分配。
// 编辑 //
- 内存池显然不一定分配在堆栈上,即。内存池可以与动态内存一起使用。
- 非动态内存显然也不一定在堆栈上分配,根据这个问题的答案。
- 'dynamic vs. static memory' 和 'memory pools' 的主题因此并不真正相关,尽管答案仍然相关。
据我所知,内存池的目的是提供 RAM 的手动管理,其中内存必须由程序员跟踪和重用。
这在理论上有利于性能,原因有很多:
- 随着时间的推移,动态内存变得碎片化
- CPU 可以比动态块更快地解析静态内存块
- 当程序员可以控制内存时,他们可以根据特定程序选择在最佳时机释放和重建数据。
4.多线程时,separate pools允许单独的线程独立运行,无需等待共享堆(Davislor)
我对内存池的理解是否正确?如果是这样,为什么内存池似乎不经常使用?
自定义分配器可以提高性能,因为默认分配器针对特定用例进行了优化,这种用例很少分配大块内存。
但是,例如在模拟器或游戏中,您可能会在一帧中发生很多事情,非常频繁地分配和释放内存。在这种情况下,默认分配器不是很好。
一个简单的解决方案是为一帧期间发生的所有一次性事件分配一块内存。这块内存可以一遍又一遍地覆盖,删除可以推迟到以后。例如:游戏关卡结束或其他。
似乎这个问题被 XY problem and premature optimisation 所阻碍。
您应该专注于编写易读代码,然后使用分析器执行优化如有必要。
Is my understanding of memory pools correct?
不完全是。
... on the stack ...
... on the heap ...
存储持续时间与池的概念正交; 池可以分配为具有四种存储持续时间任何(它们是:静态、线程、自动和动态存储持续时间)。
C++ 标准不要求 任何 进入 堆栈 或 堆;将它们全部视为进入同一个地方可能会很有用...毕竟,它们都(通常)进入硅片!
... allocate ... before runtime ...
重要的是多个对象的分配发生在之前(或至少少于)这些对象首次被使用;这样就不必单独分配每个对象。我假设这就是您所说的“在 运行time 之前”的意思。选择分配大小时,在任何给定时间越接近所需的对象总数,过度分配造成的浪费和过度调整大小造成的浪费就越少。
但是,如果您的 OS 不是史前的,游泳池的优势将很快消失。如果您在 之前和之后 进行优化,您可能会看到这一点!
- Dynamic memory becomes fragmented over time
这对于 Windows 1.0 等天真的操作系统可能是正确的。然而,在当今时代,具有分配存储持续时间的对象通常存储在 虚拟内存 中,它会定期写入并从磁盘读回(这称为 分页)。因此,可以对碎片化的内存进行碎片整理,更常用的对象、函数和方法甚至可能最终合并到公共 页.
即paging为你形成一个隐含的pool(以及cache prediction) !
The CPU can parse static blocks of memory faster than dynamic blocks
虽然分配了静态存储持续时间的对象通常位于堆栈上,但 C++ 标准并未强制要求这样做。完全有可能存在 C++ 实现,其中 静态内存块 被分配 在堆 上。
动态对象的缓存命中与静态对象的缓存命中一样快。 堆栈 通常保存在缓存中;你应该尝试没有堆栈的编程一段时间,你可能会发现缓存有更多空间用于堆!
在优化之前,您应该始终使用分析器来衡量最重要的瓶颈!然后您应该执行优化,然后运行再次分析器以确保优化成功!
这不是一个独立于机器的进程!您需要优化 per-implementation! 对一个实现的优化可能对另一个实现悲观。
If so, why does it seem like memory pools are not used very often?
上面描述的虚拟内存抽象,结合使用缓存分析器消除猜测实际上消除了池在所有方面的用处但信息最少的(即使用分析器)场景。
内存池用于实现自定义分配器。
一种常用的是线性分配器。它只保留一个指针分隔 allocated/free 内存。用它分配只是将指针递增所请求的 N 个字节,然后返回它之前的值。释放是通过将指针重置为池的开始来完成的。