您需要 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,剩下 7 个字节,不足 2 GB。
编辑:
但是等等,还有更多!
环顾四周并与 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 文章的回应):
看起来您所指的文章只是从限制中推断出开销,这是
愚蠢的IMO。
因此,要回答您的问题,根据我的收集,实际开销是24 字节和32 字节的备用空间。