Summary
很可能有some使用太大储备金的缺点,但多少取决于您的规模和背景reserve()
以及您的特定分配器、操作系统及其配置。
您可能知道,在 Windows 和 Linux 等平台上,大型分配通常在首次访问之前不会分配任何物理内存或页表条目,因此您可能会认为大型未使用的分配是“空闲”的。有时这被称为“保留”内存而不“提交”它,我将在这里使用这些术语。
以下是这可能不像您想象的那么免费的一些原因:
页面粒度
上面描述的惰性提交仅发生在页面粒度上。如果您使用(典型的)4096 字节页面,则意味着如果您通常为通常包含占用 100 字节的元素的向量保留 4,000 字节,则惰性提交不会给您带来任何好处!至少必须提交 4096 字节的整个页面,并且不会节省物理内存。因此,重要的不仅仅是预期大小与保留大小之间的比率,而是保留大小的绝对大小决定了您将看到多少浪费。
请记住,许多系统现在都透明地使用“大页面”,因此在某些情况下,粒度将达到 2 MB 或更多。在这种情况下,您需要分配大约 10 或 100 MB 的内存才能真正利用惰性分配策略。
更差的配置表现
C++ 的内存分配器通常会尝试分配大块内存(例如,通过sbrk
or mmap
在类 Unix 平台上),然后有效地将其分割成应用程序请求的小块。通过系统调用获取这些大块内存,例如mmap
可能比分配器内的快速路径分配慢几个数量级,分配器通常只有十几条指令左右。当您请求您通常不会使用的大块时,您就会失败该优化,并且您通常会走上缓慢的道路。
作为一个具体的例子,假设你的分配器要求mmap
它划分 128 KB 的块以满足分配。您在典型的情况下分配了大约 2K 的内容vector
, but reserve
64K。您现在需要支付mmap
互相呼唤reserve
打电话,但如果你只要求你最终需要的 2K,你会有大约 32times fewer mmap
calls.
对过度使用处理的依赖
当您请求大量内存但不使用它时,您可能会遇到这样的情况:您请求的内存超出了系统支持的内存(例如,超出了 RAM + 交换区)。这是否均匀allowed取决于您的操作系统及其配置方式,并且无论您是否准备好一些有趣的行为,如果您随后仅通过写入来提交更多内存。我的意思是任意进程可能会被终止,或者您可能会在任何内存写入时遇到意外错误。由于不同的原因,在一个系统上有效的方法可能在另一个系统上失败过度使用可调参数.
最后,它使管理您的流程变得更加困难,因为监视工具报告的“VM 大小”指标与您的流程最终可能提交的内容没有太大关系。
更糟糕的地方
分配比您需要的更多的内存可能会使您的工作集在虚拟地址空间中分布得更加稀疏。总体效果是参考局部性的减少。对于非常小的分配(例如,几十个字节),这可能会减少同一缓存行内的局部性,但对于较大的大小,主要影响可能是将数据分散到更多的物理页上,从而增加 TLB 压力。确切的阈值很大程度上取决于细节,例如是否启用大页面。