我知道局部变量会有序的存放在栈中。
但是,当我像这样在 C++ 的堆内存中动态分配变量时。
int * a = new int{1};
int * a2 = new int{2};
int * a3 = new int{3};
int * a4 = new int{4};
问题 1:这些变量是否存储在连续的内存位置? 问题2:如果不是,是不是因为动态分配将变量存储在堆内存中的随机位置? 问题3:那么动态分配是否会增加缓存未命中的可能性并且具有低空间局部性?
最佳答案
第 1 部分:单独分配是否连续?
答案是可能不会。动态分配如何发生取决于实现。如果您像上面的示例一样分配内存,则两个单独的分配可能 是连续的,但不能保证会发生这种情况(并且永远不应该依赖它发生)。
C++ 的不同实现使用不同的算法来决定如何分配内存。
第 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*>
.
通过扩展,如果您可以使用静态多态性(即模板),请使用它而不是动态多态性。
关于c++ - 动态分配将数据存储在堆中的随机位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55194751/