你需要56字节的开销。实际上是2,147,483,649-1减去56得到的最大大小。这就是为什么你的“减57”有效而“减56”无效。
正如Jon Skeet在这里所说:
然而,在实际情况下,我不相信任何实现支持如此巨大的数组。CLR有一个比2GB稍短的每个对象限制,因此即使是一个字节数组,也不能实际拥有2147483648个元素。一些实验表明,在我的机器上,您可以创建的最大数组是new byte [2147483591]。(这是在64位.NET CLR上;我安装的Mono版本无法处理它。)
请参见InformIT文章中关于同一主题的内容。它提供了以下代码以演示最大大小和开销:
class Program
{
static void Main(string[] args)
{
AllocateMaxSize<byte>();
AllocateMaxSize<short>();
AllocateMaxSize<int>();
AllocateMaxSize<long>();
AllocateMaxSize<object>();
}
const long twogigLimit = ((long)2 * 1024 * 1024 * 1024) - 1;
static void AllocateMaxSize<T>()
{
int twogig = (int)twogigLimit;
int num;
Type tt = typeof(T);
if (tt.IsValueType)
{
num = twogig / Marshal.SizeOf(typeof(T));
}
else
{
num = twogig / IntPtr.Size;
}
T[] buff;
bool success = false;
do
{
try
{
buff = new T[num];
success = true;
}
catch (OutOfMemoryException)
{
--num;
}
} while (!success);
Console.WriteLine("Maximum size of {0}[] is {1:N0} items.", typeof(T).ToString(), num);
}
}
最后,文章说:
如果你算一下,你会发现分配一个数组的开销是56字节。由于对象大小,末尾还剩下一些字节。例如,268,435,448个64位数字占用2,147,483,584字节。加上56字节的数组开销,总共是2,147,483,640,离2GB还差7个字节。
编辑:
但等等,还有更多!
四处寻找并与Jon Skeet交谈后,他指向了他写的关于内存和字符串的一篇文章。在那篇文章中,他提供了一个大小表:
Type x86 size x64 size
object 12 24
object[] 16 + length * 4 32 + length * 8
int[] 12 + length * 4 28 + length * 4
byte[] 12 + length 24 + length
string 14 + length * 2 26 + length * 2
斯基特先生接着说:
你看到上面的数字可能会以为在x86中一个对象的“开销”是12个字节,在x64中是24个字节……但实际上不完全是这样。
还有这段话:
在x86中每个对象的“基本”开销为8个字节,在x64中为16个字节……鉴于我们可以在x86中存储一个Int32的“真实”数据并仍然具有12个字节的对象大小,同样地,我们可以在x64中存储两个Int32的真实数据并仍然具有x64的对象。
有一个“最小”大小分别为12字节和24字节。换句话说,您不能只有开销的类型。请注意,“Empty”类占用与创建Object实例相同的大小……实际上有一些多余的空间,因为CLR不喜欢操作没有数据的对象。(请注意,即使对于局部变量,没有字段的结构体也会占用空间。)
x86对象填充到4字节边界;在x64上是8字节(就像以前一样)
最后,Jon Skeet在另一个问题中回答了我提出的问题,他在回答中表示(针对我向他展示的InformIT文章):
看起来你所提到的文章仅从限制中推断开销,这在我看来是愚蠢的。
因此,根据我所了解的情况,实际开销为24字节,剩余32字节的空间。