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

问题描述 投票:3回答:3

我知道局部变量将按顺序存储在堆栈中。

但是,当我像这样在c ++中的堆内存中动态分配变量时。

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

问题1:这些变量是否存储在连续的内存位置?问题2:如果没有,是因为动态分配存储变量在堆内存中的随机位置?问题3:动态分配是否会增加缓存未命中的可能性并且空间局部性较低?

c++ caching heap dynamic-memory-allocation
3个回答
1
投票

第1部分:单独的分配是连续的吗?

答案可能不是。动态分配如何发生依赖于实现。如果你像上面的例子那样分配内存,那么两个单独的分配可能是连续的,但是不能保证这种情况发生(并且永远不应该依赖它发生)。

c ++的不同实现使用不同的算法来决定如何分配内存。

第2部分:分配随机吗?

有些;但并非完全。内存不会以故意随机的方式分配。通常,内存分配器会尝试在彼此附近分配内存块,以便最大限度地减少页面错误和缓存未命中,但并不总是这样做。

分配分两个阶段进行:

  1. 分配器要求操作系统提供大量内存
  2. 获取那个大块的片段,并在你调用new时返回它们,直到你要求的内存超过它必须提供的内存,在这种情况下,它要求操作系统中的另一个大块。

第二个阶段是一个实现可以尝试给你的内存提供接近其他最近分配的内容,但它几乎无法控制第一个阶段(操作系统通常只提供任何可用的内存,而不知道你的其他分配程序)。

第3部分:避免缓存未命中

如果缓存未命中是代码中的瓶颈,

  • 尝试减少间接量(通过让数组按值存储对象,而不是通过指针);
  • 确保您正在操作的内存与设计允许的连续(因此使用std :: array或std :: vector,而不是链接列表,并且更喜欢对许多小内容进行一些大的分配);和
  • 尝试设计算法,使其尽可能少地在内存中跳转。

一个好的一般原则是只使用std :: vector对象,除非你有充分的理由使用更高级的东西。因为它们具有更好的缓存局部性,所以std :: vector在插入和删除元素方面比std :: list更快,甚至多达几十甚至几百个元素。

最后:尝试利用堆栈。除非有一个很好的理由让某些东西成为指针,否则只需将其声明为存在于堆栈中的变量。如果可能,

  • 更喜欢使用MyClass x{};而不是MyClass* x = new MyClass{};,和
  • 更喜欢std::vector<MyClass>而不是std::vector<MyClass*>

通过扩展,如果您可以使用静态多态(即模板),请使用它而不是动态多态。


0
投票

恕我直言这是操作系统特定/ C ++标准库实现。

new最终使用较低级别的虚拟内存分配服务,并使用mmap和munmap等系统调用一次分配多个页面。 new的实现可以在相关时重用以前释放的内存空间。 new的实施可以使用各种不同的策略进行“大”和“小”分配。

在示例中,您给出了第一个new结果系统调用内存分配(通常是几页),分配的内存可能足够大,以便随后的new调用导致连续分配。但这取决于实现


0
投票

简而言之:

  1. 根本没有(由于对齐,堆内务数据,分配的块可以重复使用,等等),
  2. 根本没有(AFAIK,堆算法是确定性的,没有任何随机性),
  3. 通常是(例如,内存池可能有帮助)。
© www.soinside.com 2019 - 2024. All rights reserved.