简体   繁体   English

动态分配在堆中的随机位置存储数据?

[英]Dynamic allocation store data in random location in the heap?

I know that local variables will be stored on the stack orderly. 我知道局部变量将按顺序存储在堆栈中。

but, when i dynamically allocate variable in the heap memory in c++ like this. 但是,当我像这样在c ++中的堆内存中动态分配变量时。

int * a = new int{1};
int * a2 = new int{2};
int * a3 = new int{3};
int * a4 = new int{4};

Question 1 : are these variable stored in contiguous memory location? 问题1:这些变量是否存储在连续的内存位置? Question 2 : if not, is it because dynamic allocation store variables in random location in the heap memory? 问题2:如果没有,是因为动态分配存储变量在堆内存中的随机位置? Question3 : so does dynamic allocation increase possibility of cache miss and has low spatial locality? 问题3:动态分配是否会增加缓存未命中的可能性并且空间局部性较低?

Part 1: Are separate allocations contiguous? 第1部分:单独的分配是连续的吗?

The answer is probably not . 答案可能不是 How dynamic allocation occurs is implementation dependent. 动态分配如何发生依赖于实现。 If you allocate memory like in the above example, two separate allocations might be contiguous, but there is no guarantee of this happening (and it should never be relied on to occur). 如果你像上面的例子那样分配内存,那么两个单独的分配可能是连续的,但是不能保证这种情况发生(并且永远不应该依赖它发生)。

Different implementations of c++ use different algorithms for deciding how memory is allocated. c ++的不同实现使用不同的算法来决定如何分配内存。

Part 2: Is allocation random? 第2部分:分配随机吗?

Somewhat; 有些; but not entirely. 但并非完全。 Memory doesn't get allocated in an intentionally random fashion. 内存不会以故意随机的方式分配。 Oftentimes memory allocators will try to allocate blocks of memory near each other in order to minimize page faults and cache misses, but it's not always possible to do so. 通常,内存分配器会尝试在彼此附近分配内存块,以便最大限度地减少页面错误和缓存未命中,但并不总是这样做。

Allocation happens in two stages: 分配分两个阶段进行:

  1. The allocator asks for a large chunk of memory from the OS 分配器要求操作系统提供大量内存
  2. The takes pieces of that large chunk and returns them whenever you call new, until you ask for more memory than it has to give, in which case it asks for another large chunk from the OS. 获取那个大块的片段,并在你调用new时返回它们,直到你要求的内存超过它必须提供的内存,在这种情况下,它要求操作系统中的另一个大块。

This second stage is where an implementation can make attempts to give things you memory that's near other recent allocations, however it has little control over the first stage (and the OS usually just provides whatever memory is available, without any knowledge of other allocations by your program). 第二阶段是一个实现可以尝试给你的内存提供接近其他最近分配的内容,但是它几乎无法控制第一阶段(操作系统通常只提供任何可用的内存,而不知道你的其他分配程序)。

Part 3: avoiding cache misses 第3部分:避免缓存未命中

If cache misses are a bottleneck in your code, 如果缓存未命中是代码中的瓶颈,

  • Try to reduce the amount of indirection (by having arrays store objects by value, rather than by pointer); 尝试减少间接量(通过让数组按值存储对象,而不是通过指针);
  • Ensure that the memory you're operating on is as contiguous as the design permits (so use a std::array or std::vector, instead of a linked list, and prefer a few big allocations to lots of small ones); 确保您正在操作的内存与设计允许的连续(因此使用std :: array或std :: vector,而不是链接列表,并且更喜欢对许多小内容进行一些大的分配); and
  • Try to design the algorithm so that it has to jump around in memory as little as possible. 尝试设计算法,使其尽可能少地在内存中跳转。

A good general principle is to just use a std::vector of objects, unless you have a good reason to use something fancier. 一个好的一般原则是只使用std :: vector对象,除非你有充分的理由使用更高级的东西。 Because they have better cache locality, std::vector is faster at inserting and deleting elements than std::list, even up to dozens or even hundreds of elements. 因为它们具有更好的缓存局部性,所以std :: vector在插入和删除元素方面比std :: list更快,甚至多达几十甚至几百个元素。

Finally: try to take advantage of the stack. 最后:尝试利用堆栈。 Unless there's a good reason for something to be a pointer, just declare as a variable that lives on the stack. 除非有一个很好的理由让某些东西成为指针,否则只需将其声明为存在于堆栈中的变量。 When possible, 若有可能,

  • Prefer to use MyClass x{}; 更喜欢使用MyClass x{}; instead of MyClass* x = new MyClass{}; 而不是MyClass* x = new MyClass{}; , and ,和
  • Prefer std::vector<MyClass> instead of std::vector<MyClass*> . 首选std::vector<MyClass>而不是std::vector<MyClass*>

By extension, if you can use static polymorphism (ie, templates), use that instead of dynamic polymorphism. 通过扩展,如果您可以使用静态多态(即模板),请使用它而不是动态多态。

IMHO this is Operating System specific / C++ standard library implementation. 恕我直言这是操作系统特定/ C ++标准库实现。

new ultimately uses lower-level virtual memory allocation services and allocating several pages at once, using system calls like mmap and munmap. new最终使用较低级别的虚拟内存分配服务,并使用mmap和munmap等系统调用一次分配多个页面。 The implementation of new could reuse previously freed memory space when relevant. new的实现可以在相关时重用以前释放的内存空间。 The implementation of new could use various and different strategies for "large" and "small" allocations. new的实施可以使用各种不同的“大”和“小”分配策略。

In the example you gave the first new results in a system call for memory allocation (usually several pages), the allocated memory could be large enough so that subsequent new calls results in contiguous allocation..But this depends on the implementation 在示例中,您在系统调用内存分配(通常是几页)中给出了第一个new结果,分配的内存可能足够大,以便后续的new调用导致连续分配。但这取决于实现

In short: 简而言之:

  1. not at all (there is padding due to alignment, heap housekeeping data, allocated chunks may be reused, etc.), 根本没有 (由于对齐,堆内务数据,分配的块可以重复使用,等等),

  2. not at all (AFAIK, heap algorithms are deterministic without any randomness), 根本没有 (AFAIK,堆算法是确定性的,没有任何随机性),

  3. generally yes (eg, memory pooling might help here). 通常是 (例如,内存池可能在这里有所帮助)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM