我浏览了video by Bjarne Stroustrup,在那里他解释了为什么要避免链接列表。
基本上,当使用指针动态分配内存时,有更多的缓存未命中会降低性能。
但是,如果同样的事情适用于非线性数据结构,如树木和图形,那么同样的事情也适用吗?
因为在树中我们每个节点都有两个指针,并且指针会随机移动导致缓存未命中。
但是,树已被证明比线性数据结构表现更好。当然,树也可以使用数组实现,但同样存在大量的内存消耗。
我的问题是:动态内存分配是否良好?
答案 0 :(得分:7)
他试图指出小对象之间的大量间接会降低代码的缓存效率。你不能完全避免链接的结构,但在某些情况下你可能更喜欢"扁平"例如,布局适合整个缓存行。
树和链接列表都是依赖于动态内存分配的链接结构,但列表被认为是“错误的”#34;因为它们是O(n)
,并且next
指针几乎每次追逐都会导致缓存未命中。一般来说,n
未命中比log(n)
未命中要差很多。
例如,请考虑以下两个结构:
struct point {
int x, y;
};
struct rect {
struct point origin;
struct point size;
};
尽管rect
包含两个point
结构,但整个rect
结构完全是"平坦的"因为包含内部结构,而不是通过指针引用。这种平坦性是一件好事,因为rect
现在可以放在缓存行上,例如,访问origin.x
不会在结构本身的初始值之后导致缓存未命中。 / p>
此外,因为堆栈通常是热的"在缓存中,在那里分配整个rect
结构是有意义的,而不是在堆上。它不仅是动态分配本身的开销,而且分配器返回的地址可能还没有在缓存中。
答案 1 :(得分:2)
数据结构是一个抽象概念。它们与语言无关,更不用于实现其中一些语言的库(在本例中为std
)。
树在查找方面比在数组中更好,因为内存是静态分配或动态分配的(对于两个数据结构都可以),但是由于用于搜索它的算法。
然而,在遍历所有节点时,通常情况下,数组的性能优于树(因为更简单的算法和实现细节 - 由于线性分配而更快的缓存)。 / p>
更好地使用对您计划对其执行的操作有意义的数据结构。您始终可以提供处理分配的自定义分配器。但是,再次,分配是正交的。算法效率高,效率低。这是一个权衡。如果你足够分离你的设计,你应该能够轻松地在数据结构之间切换,并且如果性能受到足够的影响就可以做到。
答案 2 :(得分:0)
是否要动态分配内存或在堆栈上分配内存完全取决于您的实现。通常,如果变量或对象仅存在于函数内部,则使用堆栈;如果变量或对象必须存在于整个程序中并由多个函数操作,则使用堆。