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

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

int? i = null;

和:

int? i = 3;

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

【问题讨论】:

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

标签: c# .net memory nullable


【解决方案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;的大小完全取决于类型。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-02-20
            • 2010-09-13
            • 1970-01-01
            • 1970-01-01
            • 2017-02-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多