Reserve()的高估有不利之处吗? [英] Is there a downside to a significant overestimation in a reserve()?

查看:126
本文介绍了Reserve()的高估有不利之处吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有一个方法可以创建并使用可能很大的 vector< foo> s。
元素的最大数量已知为 maxElems

Let's suppose we have a method that creates and uses possibly very big vector<foo>s. The maximum number of elements is known to be maxElems.

C ++的标准做法据我所知,11是:

Standard practice as of C++11 is to my best knowledge:

vector<foo> fooVec;
fooVec.reserve(maxElems);
//... fill fooVec using emplace_back() / push_back()

但是如果在我们的大多数方法调用中元素的数量将大大减少的情况下会发生这种情况?

But what happens if we have a scenario where the number of elements is going to be significantly less in the majority of calls to our method?

保守的<$是否有不利之处? c $ c> reserve 调用,而不是多余的已分配内存(如果需要,可以通过 shrink_to_fit()释放)?

Is there any disadvantage to the conservative reserve call other than the excess allocated memory (which supposably can be be freed with shrink_to_fit() if necessary)?

推荐答案

摘要



可能有些一些使用太大的预留空间是不利的,但是多少取决于 reserve()的大小和上下文以及您的特定分配器,操作系统及其组态。

Summary

There is likely to be some downside to using a too-large reserve, but how much is depends both on the size and context of your reserve() as well as your specific allocator, operating system and their configuration.

您可能已经知道,在Windows和Linux之类的平台上,大容量分配通常不会分配任何物理内存或页表条目,直到您对其进行首次访问为止,因此您可能想象大量未使用的分配是免费的。有时这被称为保留内存而没有提交内存,我将在这里使用这些术语。

As you are probably aware, on platforms like Windows and Linux, large allocations are generally not allocating any physical memory or page table entries until it is first accessed, so you might imagine large, unused allocations to be "free". Sometimes this is called "reserving" memory without "committing" it, and I'll use those terms here.

以下是某些原因,它可能不如您所愿想象一下:

Here are some reasons this might not be as free as you'd imagine:

上述的惰性提交仅在页面粒度下发生。如果您正在使用(典型)4096个字节的页面,则意味着如果您通常为一个向量保留4,000个字节,而该向量通常包含占用100个字节的元素,那么惰性提交不会为您带来任何好处!至少必须提交整个4096字节的页面,并且您不节省物理内存。因此,重要的不只是预期大小与保留大小之间的比率,而是保留大小的绝对大小决定了您将看到多少浪费。

The lazy commit described above only happens at a page granularity. If you are using (typical) 4096 byte pages, it means that if you usually reserve 4,000 bytes for a vector that will usually contains elements taking up 100 bytes, the lazy commit buys you nothing! At least the whole page of 4096 bytes has to be committed and you don't save physical memory. So it isn't just the ratio between the expected and reserved size that matters, but the absolute size of the reserved size that determines how much waste you'll see.

请记住,许多系统现在都在透明地使用大页面,因此在某些情况下,粒度大约为2 MB或更大。在这种情况下,您需要大约10s或100s MB的分配才能真正利用惰性分配策略。

Keep in mind that many systems are now using "huge pages" transparently, so in some cases the granularity will be on the order of 2 MB or more. In that case you need allocations on the order of 10s or 100s of MB to really take advantage of the lazy allocation strategy.

C ++的内存分配器通常尝试分配大块内存(例如,通过 sbrk mmap (在类似Unix的平台上),然后将其有效地分解为应用程序所请求的小块。通过诸如 mmap 之类的系统调用来获取这些大块内存可能比分配器中的快速路径分配(通常只有十几条指令)慢几个数量级。 。当您要求大块的块而您通常不会使用的块块时,您就会失去优化效果,并且通常会走缓慢的道路。

Memory allocators for C++ generally try to allocate large chunks of memory (e.g., via sbrk or mmap on Unix-like platforms) and then efficiently carve that up into the small chunks the application is requesting. Getting these large chunks of memory via say a system call like mmap may be several orders of magnitude slower than the fast path allocation within the allocator which is often only a dozen instructions or so. When you ask for large chunks that you mostly won't use, you defeat that optimization and you'll often be going down the slow path.

作为一个具体示例,假设您的分配器要求 mmap 分配128 KB的块,它可以满足分配要求。您在典型的向量中分配了大约2K的东西,但是保留的64K。现在,您将为每隔储备金呼叫支付一次 mmap 呼叫,但是如果您只是要求2K,则最终需要,您的 mmap 调用将减少约32个次。

As a concrete example, let's say your allocator asks mmap for chunks of 128 KB which it carves up to satisfy allocations. You are allocating about 2K of stuff in a typical vector, but reserve 64K. You'll now pay a mmap call for every other reserve call, but if you just asked for the 2K you ultimately needed, you'd have about 32 times fewer mmap calls.

当您请求大量内存而不使用时,您可能会遇到以下情况:请求的内存超出系统支持(例如,超过您的RAM +交换)。是否允许使用 取决于您的操作系统及其配置方式,并且如果您随后通过编写更多内存来承担更多有趣的行为,则不管您要做什么。我的意思是任意进程可能会被杀死,或者您在任何内存写入时都可能会遇到意外错误。由于不同的过量使用可调参数,在一个系统上可以正常工作的系统可能在另一个系统上失败

When you ask for a lot of memory and don't use it, you can get into the situation where you've asked for more memory than your system supports (e.g., more than your RAM + swap). Whether this is even allowed depends on your OS and how it is configured, and no matter what you are up for some interesting behavior if you subsequently commit more memory simply by writing it. I means that arbitrary processes may be killed, or you might get unexpected errors on any memory write. What works on one system may fail on another due to different overcommit tunables.

最后,由于监视工具报告的 VM大小指标与您的流程最终可能没有太大关系,因此使您的流程管理更加困难

Finally, it makes managing your process a bit harder since the "VM size" metric as reported by monitoring tools won't have much relationship to what your process may ultimately commit.

分配的内存超过了您的需要,这可能会使您的工作集变得更多稀疏散布在虚拟地址空间中。总体效果是减少了参考位置。对于很小的分配(例如几十个字节),这可能会减少缓存行内的局部性,但是对于较大的分配,主要的影响可能是将数据分散到更多的物理页面上,从而增加了TLB压力。确切的阈值在很大程度上取决于细节,例如是否启用了大页面。

Allocating more memory than you need makes it likely that your working set will be more sparsely spread out in the virtual address space. The overall effect is a reduction in locality of reference. For very small allocations (e.g., a few dozen bytes) this may reduce the within-same-cache-line locality, but for larger sizes the main effect is likely to be to spread your data onto more physical pages, increasing TLB pressure. The exact thresholds will depend a lot on details like whether hugepages are enabled.

这篇关于Reserve()的高估有不利之处吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆