svi*_*ick 28 .net arrays limits
在我的64位机器上,这个C#代码有效:
new byte[2L * 1024 * 1024 * 1024 - 57]
Run Code Online (Sandbox Code Playgroud)
但是这个抛出一个OutOfMemoryException
:
new byte[2L * 1024 * 1024 * 1024 - 56]
Run Code Online (Sandbox Code Playgroud)
为什么?
我知道托管对象的最大大小是2 GB,我正在创建的数组对象包含的内容超过了我想要的字节数.也就是说,同步块编号有4个字节(或8?),MethodTable参考有8个字节,数组大小有4个字节.这是24个字节,包括填充,所以为什么我不能分配一个2G-24字节的数组?最大尺寸真的是 2 GB吗?如果是这样的话,2 GB的剩余部分用于什么?
注意:我实际上不需要分配一个包含200万字节的数组.即使我这样做,56个字节的开销可以忽略不计.我可以使用自定义轻松解决限制BigArray<T>
.
小智 20
您需要56个字节的开销.最大尺寸实际上是2,147,483,649-1 减去 56.这就是为什么你的减去 57工作而减去 56工作没有.
正如Jon Skeet在这里所说:
但是,实际上,我认为任何实现都不支持这样庞大的数组.CLR的每个对象限制有点短于2GB,因此即使是字节数组也不能实际具有2147483648个元素.一些实验表明,在我的盒子上,你可以创建的最大数组是新字节[2147483591].(这是在64位.NET CLR上; Mono的版本已经安装了choke.)
另请参阅有关同一主题的此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);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,文章有这样的说法:
如果你做数学运算,你会发现分配数组的开销是56字节.由于对象大小,最后会留下一些字节.例如,268,435,448个64位数字占用2,147,483,584字节.添加56字节的数组开销为您提供2,147,483,640,留下7字节短2千兆字节.
编辑:
但等等,还有更多!
环顾四周并与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
Run Code Online (Sandbox Code Playgroud)
斯凯特先生接着说:
你可能会因为查看上面的数字而认为对象的"开销"在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字节的备用空间.