15年前,在使用Pascal进行编程时,我理解为什么要使用2的幂来进行内存分配。但这似乎仍然是最先进的。
C#示例:
new StringBuilder(256);
new byte[1024];
int bufferSize = 1 << 12;
我仍然看到这几千次,我自己用这个,我还在质疑:
我们是否需要现代编程语言和现代硬件? 我猜它是好习惯,但是原因是什么?
修改
例如一个byte[]
数组,如答案所述,2的幂是没有意义的:数组本身将使用16个字节(?),因此使用240(= 256-16)是有意义的大小总共256个字节?
答案 0 :(得分:4)
我们是否需要现代编程语言和现代硬件?我想这是好习惯,但是原因是什么?
这取决于。这里有两件事需要考虑:
假设您正在使用malloc()
进行低级别分配,使用页面大小的倍数将被视为一个好主意,即4096或8192;这是因为它允许更有效的内存管理。
我的建议是只分配你需要的东西,让C#为你处理内存管理和分配。
答案 1 :(得分:2)
byte[] arr = new byte[4096];
fixed (byte* p = arr)
{
int size = ((int*)p)[IntPtr.Size == 4 ? -1 : -2];
}
所以CLR已经分配了至少4096 +(1或2)sizeof(int)......所以它已经超过了一个4k的内存页面。这是合乎逻辑的...它必须将数组的大小保持在某个位置,并且将它与数组保持在一起是最聪明的事情(对于那些知道Pascal Strings和BSTR
是什么的人,是的,它&#39 ; s原则相同)
我要补充一点,.NET中的所有对象都有一个syncblck编号和一个RuntimeType
...如果不是int
,它们至少是IntPtr
,所以总计8到16个字节/对象之间(这在不同的地方解释...如果你有兴趣,试着寻找.net object header
)
答案 2 :(得分:1)
在某些情况下仍然有意义,但我更愿意逐案分析是否需要这种规范,而不是盲目地将其用作良好做法。
例如,在某些情况下,您可能希望使用正好8位的信息(1个字节)来处理表。
在这种情况下,我会让表格的大小为2 ^ 8。
Object table = new Object[256];
通过这种方式,您只需使用一个byte
即可解决该表的任何对象。
即使表实际上较小并且不使用所有256个位置,您仍然可以保证从表到索引以及从索引到表的双向映射,这可以防止出现的错误,例如,如果您有:
Object table = new Object[100];
然后有人(可能是其他人)使用表格范围之外的字节值来访问它。
也许这种双射行为可能是好的,也许你可以有其他方法来保证你的约束。
可能,鉴于当前编译器的智能性提高,它不再是唯一的良好实践。
答案 3 :(得分:0)
发现这可能重复:Is it better to allocate memory in the power of two?
答案 4 :(得分:0)
是的,这是一种很好的做法,至少有一个原因。 现代处理器的L1缓存行大小为64字节,如果您将缓冲区大小用作2 ^ n(例如1024,4096,..),您将使用完全缓存行,而不会浪费空间。 在某些情况下,这有助于防止错误共享问题(http://en.wikipedia.org/wiki/False_sharing)。