Nullable<T> 的内存占用是多少

Posted

技术标签:

【中文标题】Nullable<T> 的内存占用是多少【英文标题】:What is the memory footprint of a Nullable<T> 【发布时间】:2010-11-25 18:17:59 【问题描述】:

int (Int32) 的内存占用为 4 个字节。但是什么是内存占用:

int? i = null;

和:

int? i = 3;

这是一般情况还是取决于类型?

【问题讨论】:

在任何情况下,你是否有一个值,或者它是“null”都没有关系。无论如何,它将占用相同数量的字节。 【参考方案1】:

我不是 100% 确定,但我相信它应该是 8 个字节,int32 应该是 4 个字节,并且(因为在 32 位机器上每件事都必须是 4 字节对齐)另外 4 个字节作为布尔值表示是否指定了整数值。

注意,感谢@sensorSmith,我现在知道 .Net 的较新版本允许可空值存储在更小的占用空间中(当硬件内存设计允许独立分配更小的内存块时)。在 64 位机器上,它仍然是 8 字节(64 位),因为这是可以寻址的最小内存块......

例如,可为空的布尔值只需要一个位,IsNull 标志需要另一个位,因此总存储要求小于一个字节,理论上它可以存储在一个字节中,但是,像往常一样,如果可以分配的最小内存块是 8 字节(如在 64 位机器上),那么它仍将占用 8 字节内存。

【讨论】:

一台 64 位机器有一个 64 位(8 字节)宽的总线,因此,据我了解,每次数据获取(或写入)都会从内存中带回 64 位(8 字节)。跨度> 装箱后大小再次不同,因为 Nullable 消失了,因此它要么是 null,要么是装箱的 int。 布尔值不是 4 个字节。 According to MSDN sizeof(bool) 返回 1,因此 Nullable&lt;Int32&gt; 将占用 5 个字节。我不认为填充添加到结构的末尾。 @Virtlink true,但实际上由于大部分时间内存对齐,布尔值占用 4 个字节。例如,当有一个 Nullable. 数组时 sizeof 给出错误,并建议改用 System.Runtime.InteropServices.Marshal.SizeOf。但这会返回 8 个字节的双倍?然后我试着写一个double? value 转换成一个字节数组,结果使用了 16 个字节。我错了,还是这效率极低? 7个字节对齐?【参考方案2】:

Nullable&lt;T&gt; 的大小绝对取决于类型。该结构有两个成员

boolean:对于 hasValue 价值:用于基础价值

结构的大小通常会映射为 4 加上类型参数 T 的大小。

【讨论】:

【参考方案3】: 诠释? a = 3; 00000038 lea ecx,[ebp-48h] 0000003b 移动 edx,3 00000040 致电 78BFD740 00000045 无 一个=空; 00000046 lea edi,[ebp-48h] 00000049 像素或 xmm0,xm​​m0 0000004d movq mmword ptr [edi],xmm0

似乎第一个 dword 是值,第二个是空标志。所以,总共 8 个字节。

很好奇,BinaryWritter 不喜欢编写可为空的类型。我在徘徊,如果它可以将它压缩到 8 个字节......

【讨论】:

在我前雇主的一个网络项目中,我们会将其编码为 33 位到数据流中。 33 位切割不好 :) 我知道。我们采用按位对齐,有时甚至采用更高级的打包,例如将 3 个三态(27 种可能性)编码为 5 位。【参考方案4】:

.NET(和大多数其他语言/框架)的默认行为是将结构字段与其大小的倍数对齐,并将结构自身与其最大字段大小的倍数对齐。参考:StructLayout

Nullable&lt;T&gt; 有一个 bool 标志和 T 值。由于 bool 只占用 1 个字节,因此最大字段的大小是 T 的大小;与单独的 T 相比,Nullable 所需的空间增加了一倍。参考:Nullable Source

澄清:如果 T 本身是一个非原始结构而不是原始类型,Nullable 会根据 T 内的最大原始字段的大小增加所需的空间,或者递归地增加任何 T 内的空间非原始字段。所以,Nullable&lt;Nullable&lt;bool&gt;&gt; 的大小是 3,而不是 4。

【讨论】:

【参考方案5】:

您可以使用类似于https://www.dotnetperls.com/nullable-memory 的代码进行检查。

我得到了以下结果:

Int32 4 个字节 Int32? 8 个字节 Int16 2 个字节 Int16? 4 个字节 Int64 8 个字节 Int64? 16 字节 Byte 1 个字节 Byte? 2 个字节 bool 1 个字节 bool? 2 个字节

【讨论】:

【参考方案6】:

int? 是一个包含布尔值 hasValue 和 int 的结构。因此,它的占用空间为 5 个字节。这同样适用于 nullable&lt;T&gt; 的所有实例:size = sizeof(T)+sizeof(bool)

【讨论】:

好点。我不太了解数据是如何打包在一起的。【参考方案7】:

可空类型是包含常规变量和空状态标志的结构。

对于一个可为空的 int,这意味着它包含五个字节的数据,但它当然会被填充到完整的单词中,因此它使用了八个字节。

您通常可以预期任何可为空的类型都将比常规类型大四个字节,字节和布尔等小类型除外。

【讨论】:

【参考方案8】:

32 位和 64 位机器:

int == 4 字节 int? == 8 字节 == 4 表示 int + 4 表示可空类型包装器。

可空类型包装器需要 4 个字节的存储空间。和整数 每个元素本身需要 4 个字节。这是一个高效的 执行。在一个数组中,许多可为空的类型存储在 连续内存。

基于个人测试(.NET Framework 4.6.1、x64、Release)并来自 – https://www.dotnetperls.com/nullable-memory

另外,如果感兴趣的话:why int on x64 equals only 4 bytes?

注意:这仅对Nullable&lt;int&gt;有效,Nullable&lt;T&gt;的大小完全取决于类型。

【讨论】:

以上是关于Nullable<T> 的内存占用是多少的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Nullable<T> 不匹配作为通用约束的引用类型 [重复]

这种 Nullable<T> 行为与隐式转换运算符的理由是啥

java中成员函数占用对象的内存空间吗

非 Nullable 类型的通用约束

Nullable不是泛型类, 但方法可以是泛型的;

IEquatable<T> 和 [AllowNull]