为什么每个人都使用2 ^ n个数字进行分配? - >新的StringBuilder(256)

时间:2013-08-13 06:03:21

标签: c# memory-management size

15年前,在使用Pascal进行编程时,我理解为什么要使用2的幂来进行内存分配。但这似乎仍然是最先进的。

C#示例:

new StringBuilder(256);
new byte[1024];
int bufferSize = 1 << 12;

我仍然看到这几千次,我自己用这个,我还在质疑:

我们是否需要现代编程语言和现代硬件? 我猜它是好习惯,但是原因是什么?

修改
例如一个byte[]数组,如答案所述,2的幂是没有意义的:数组本身将使用16个字节(?),因此使用240(= 256-16)是有意义的大小总共256个字节?

5 个答案:

答案 0 :(得分:4)

  

我们是否需要现代编程语言和现代硬件?我想这是好习惯,但是原因是什么?

这取决于。这里有两件事需要考虑:

  1. 对于小于内存页面大小的大小,分配空间的2的幂和任意数字之间没有明显差异;
  2. 您最常使用C#管理数据结构,因此您甚至不知道下面真正分配了多少字节。
  3. 假设您正在使用malloc()进行低级别分配,使用页面大小的倍数将被视为一个好主意,即4096或8192;这是因为它允许更有效的内存管理。

    我的建议是只分配你需要的东西,让C#为你处理内存管理和分配。

答案 1 :(得分:2)

可悲的是,如果你想在4k的单个记忆页面中保留一块内存,这是非常愚蠢的...而且人们甚至都不知道:-)(我没有&#39;直到10分钟前...我只有预感... ...一个例子......它是不安全的代码和实现依赖(使用.NET 4.5,32 / 64位)

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)

恕我直言,任何以两个算术运算的精确力量结束的东西就像一条快速通道。对于2的幂的低级算术运算比任何其他数字需要额外的cpu工作需要更少的转数和位操作。

发现这可能重复: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)。