为什么 Boolean 在 .NET 框架中消耗 4 个字节,而 char 消耗 2 个字节?布尔值应占用 1 位或至少小于 char。
9 回答
这是内存对齐的问题。4 字节变量的工作速度比 2 字节变量快。这就是为什么你应该使用 int 而不是 byte 或 short 作为计数器等的原因。
只有当内存比速度更重要时,才应该使用 2 字节变量。这就是为什么 char(.NET 中的 Unicode)占用两个字节而不是四个字节的原因。
关于boolean
大多数其他答案都弄错了——对齐和速度是程序员应该坚持使用 int 循环计数器的原因,而不是编译器可以使字节为 4 字节宽的原因。实际上,您的所有推理都适用于字节和短以及布尔值。
至少在 C# 中,bool(或 System.Boolean)是一个 1 字节宽的内置结构,可以自动装箱,所以你有一个对象(至少需要两个内存字来表示,即 8/在 32/64 位环境下分别为 16 个字节),一个字段(至少一个字节)加上一个指向它的内存字,即总共至少 13/25 个字节。
这确实是关于“C# 原始类型”的第一个 Google 条目。 http://msdn.microsoft.com/en-us/library/ms228360(VS.80).aspx
此外,引用的链接(http://geekswithblogs.net/cwilliams/archive/2005/09/18/54271.aspx)还指出,根据 CLI 标准,布尔值占用 1 个字节。
然而,实际上,唯一可见的地方是布尔数组 - n 个布尔值将占用 n 个字节。在其他情况下,一个布尔值可能需要 4 个字节。
- 在结构内部,大多数运行时(也在 Java 中)会将所有字段对齐到 4 字节边界以提高性能。用于嵌入式设备的 Monty JVM 更明智——我猜它以最佳方式重新排序字段。
- 在解释器的本地帧/操作数堆栈上,在大多数实现中,为了提高性能,一个堆栈条目是一个内存字宽(可能在 .NET 上,它必须是 64 位宽才能支持 double 和 long,这在 .NET 上)仅使用 1 个堆栈条目,而不是 Java 中的 2 个)。如果额外的开销是值得的,JIT 编译器可以改为将 1 个字节用于布尔局部变量,同时通过重新排序字段来保持其他变量对齐而不影响性能。
关于char
char
是两个字节,因为当需要支持国际化时,在内部使用两个字节字符是最安全的选择。这与选择支持 Unicode 没有直接关系,而是与选择坚持 UTF-16 和基本多语言平面有关。在 Java 和 C# 中,您可以一直假设一个逻辑字符适合 char 类型的变量。
这是因为在 32 位环境中,CPU 可以比 8 位或 16 位值更快地处理 32 位值,因此这是速度/大小的权衡。如果您必须节省内存并且您有大量的布尔值,只需使用uint并将您的布尔值保存为 4 字节uint的位。字符为 2 个字节宽,因为它们存储 16 位 Unicode 字符。
不管内存存储的细微差别如何,使用布尔值表示 true/false yes/no 值对开发人员(包括您自己,当您必须在一年后重新访问代码时)很重要,因为它更准确地反映了您的意图。让你的代码更容易理解比节省两个字节更重要。
使您的代码更准确地反映您的意图还可以降低某些编译器优化产生负面影响的可能性。这个建议超越了平台和编译器。
您还应该使用布尔值来帮助编写可维护的代码。如果我看一下代码,发现某些东西是布尔值,那么值得节省内存来确定您使用 char 作为布尔值。
我发现:“实际上,布尔值是 4 个字节,而不是 2 个。原因是 CLR 支持布尔值。我认为这就是它的作用,因为 32 位值的操作效率更高,因此时间/空间一般来说,权衡是值得的。如果你需要将一堆比特塞在一起,你应该使用比特向量类(忘记它在哪里)......“
它由 Paul Wick 在http://geekswithblogs.net/cwilliams/archive/2005/09/18/54271.aspx撰写
只有当您有大量位数组时,内存才是一个问题,在这种情况下,您可以使用 System.Collections.BitArray 类。
首先,您应该使用分析器来确定您在哪里有内存问题,恕我直言。