为啥布尔值比字符消耗更多的内存?
Posted
技术标签:
【中文标题】为啥布尔值比字符消耗更多的内存?【英文标题】:Why does boolean consume more memory than char?为什么布尔值比字符消耗更多的内存? 【发布时间】:2010-09-17 06:48:33 【问题描述】:为什么在 .NET 框架中一个布尔值消耗 4 个字节,一个字符消耗 2 个字节?布尔值应占用 1 位或至少小于 char。
【问题讨论】:
我也问过自己同样的问题。 出于好奇,一个结构体中的 2 个布尔值占用了多少空间? 您期望有多少个布尔值?通常值类型只会被堆栈消耗,所以除非你处理大量的布尔值(比如一串字符),否则我不会担心。 如果您有很多二进制值,请使用 System.Collections.BitArray。 您正在查看的是盒装布尔的大小,而不是真实的大小(有关详细信息,请参阅我的答案)!您选择的答案是错误的。 【参考方案1】:不管内存存储的细微差别如何,使用布尔值表示 true/false yes/no 值对开发人员(包括您自己,当您必须在一年后重新访问代码时)很重要,因为它更准确地反映了您的意图。让你的代码更易于理解比节省两个字节更重要。
使您的代码更准确地反映您的意图还可以降低某些编译器优化产生负面影响的可能性。这个建议超越了平台和编译器。
【讨论】:
【参考方案2】:您还应该使用布尔值来帮助编写可维护的代码。如果我看一下代码,发现某些东西是布尔值,那么值得节省内存来确定您使用 char 作为布尔值。
【讨论】:
【参考方案3】:关于boolean
大多数其他答案都弄错了 - 对齐和速度是程序员应该坚持使用 int 循环计数器的原因,而不是编译器可以使字节为 4 字节宽的原因。事实上,您的所有推理都适用于 byte 和 short 以及 boolean。
至少在 C# 中,bool(或 System.Boolean)是一个 1 字节宽的内置结构,可以自动装箱,所以你有一个对象(至少需要两个内存字来表示,即在 32/64 位环境中分别为 8/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 类型的变量。
【讨论】:
您可以在 C# 中使用 BMP 之外的字符,它们使用两个char
s 表示。虽然应该很少见。【参考方案4】:
这是因为 Windows 和 .Net 从一开始就使用 Unicode (UTF 16) 作为其内部字符集。 UTF 16 每个字符使用 2 个字节或每个字符使用一对 2 字节字,但仅在需要时使用,因为它是 variable width encoding。
“对于基本多语言平面 (BMP) 中的字符,生成的编码是单个 16 位字。对于其他平面中的字符,编码将生成一对 16 位字”
我对布尔值的猜测是它们是四个字节,因为默认寄存器是 32 位,这将是 .Net 可以有效执行逻辑运算的最小大小,除非使用按位运算。
【讨论】:
【参考方案5】:仅当您有大量位数组时才需要考虑内存,在这种情况下,您可以使用 System.Collections.BitArray 类。
【讨论】:
【参考方案6】:首先你应该使用分析器来确定你在哪里有内存问题,恕我直言。
【讨论】:
【参考方案7】:这是因为在 32 位环境中,CPU 可以比 8 位或 16 位值更快地处理 32 位值,因此这是速度/大小的权衡。如果你必须节省内存并且你有大量的布尔值,只需使用 uints 并将你的布尔值保存为 4 字节 uints 的位。 字符为 2 个字节宽,因为它们存储 16 位 Unicode 字符。
【讨论】:
【参考方案8】:我发现:“实际上,布尔值是 4 个字节,而不是 2 个。原因是 CLR 支持布尔值。我认为它就是这样做的,因为 32 位值的操作效率更高,所以一般来说,时间/空间的权衡是值得的。如果你需要将一堆比特塞在一起,你应该使用比特向量类(忘记它在哪里)......"
由 Paul Wick 撰写,http://geekswithblogs.net/cwilliams/archive/2005/09/18/54271.aspx
【讨论】:
嗯! .NET 应该停止为我们做决定。 @Vulcan Eager:开个玩笑吧? .NET 的全部意义在于它为我们做出了很多决定(比如垃圾收集......) 我同意 Giovanni Galbo 的观点,如果你想要完全控制,你应该在 C 或 ASM 中做一些事情。 .NET 和 C# 的美妙之处在于,此类问题由可能比我或你聪明得多的人处理。【参考方案9】:这是内存对齐的问题。 4 字节变量的工作速度比 2 字节变量快。这就是为什么你应该使用 int 而不是 byte 或 short 作为计数器等的原因。
只有当内存比速度更重要时,才应该使用 2 字节变量。这就是为什么 char(.NET 中的 Unicode)占用两个字节而不是四个字节的原因。
【讨论】:
您通常不能使用标准架构引用单个内存位,这样做效率非常低。字节通常是最小的可寻址单元,在这种情况下,一个 char 被认为是 2 个字节。 未装箱的布尔值占用 1 个字节 - 见下文;这根本不是问题的有效答案。以上是关于为啥布尔值比字符消耗更多的内存?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 ~(true^true) 不正确?布尔运算符(否定)适用于“无符号字符”,但不适用于布尔值? (C++)
为啥我的自定义 JSONEncoder.default() 忽略布尔值?