64位应用程序的内存使用开销是多少?

45

据我目前所了解的,编译为64位架构的程序使用的指针RAM比32位替代品多一倍-https://superuser.com/questions/56540/32-bit-vs-64-bit-systems

这是否意味着编译为64位的代码平均使用的RAM是32位版本的两倍?

我有点怀疑,但我想知道真正的开销是什么。我认为像 shortbytechar 这样的小类型在64位架构中大小相同?不过,我对于byte并不确定。鉴于许多应用程序使用大字符串(如Web浏览器等),这些字符串在大多数实现中主要由char数组组成,因此开销可能不会那么大。

所以,即使像 intlong 这样的数字类型在64位上更大,它们是否会对RAM的使用产生显著影响?


3
byte 不是一个标准类型。使用 C99 或更高版本,包含 <stdint.h>,然后如果您需要无符号的 8 位 "bytes",则使用 uint8_t - Basile Starynkevitch
2
内存使用量会增加,但(几乎)永远不会翻倍。 - phuclv
11
创建新的CPU,使用更宽的地址和数据总线的整个目的是为了以程序大小和RAM消耗为代价来提高执行速度。从8位到16位再到32位、64位都是如此。所以这里没有什么新的东西。 - Lundin
3
当然。内存并不重要,64位程序使用处理器缓存的效果要差得多。它的性能并不会恶化两倍,这取决于其他正在发生的事情。正因为如此,“int”的大小仍然是32位。AMD值得赞扬,他们通过添加所有正确的功能来弥补性能损失,以获得可比较的结果,从而得到了额外的8个寄存器。 - Hans Passant
1
@Pharap 这完全不正确,考虑一下半虚拟化环境或共享主机。VPS 可能也是 64 位的,但内存非常低,或者是动态内存,你需要为它付费。许多程序员犯了一个常见的错误,认为内存是非常便宜的东西,可以随意浪费。在许多情况下,你需要有效地使用内存,特别是在为数千个客户提供服务的服务器应用程序中。 - Petr
显示剩余8条评论
3个回答

42

这取决于编程风格(以及语言,但您正在参考C语言)。

  • 如果您经常使用指针(或在某些语言中有很多引用),则会增加内存消耗。
  • 如果您使用了很多固定大小的数据类型,例如doubleint32_t,则内存消耗不会增加。
  • 对于像intlong这样的类型,它取决于体系结构;在Linux和Windows之间可能存在差异。这里是您可以选择的替代方案。简而言之,Windows使用LLP64,意味着long long和指针为64位,而Linux使用LP64,其中long也为64位。其他体系结构可能会将int甚至short也设置为64位,但这些相当罕见。
  • floatdouble在所有情况下都应保持相同的大小。

所以你看,它强烈依赖于数据类型的使用方式。


1
x86-64还具有使用32位指针的x32 ABI。与使用32位x86相比,它具有更多基于寄存器的调用约定的优点,并且能够使用额外的8个GPR(和额外的8个SIMD / FP寄存器)。此外,GCC支持AArch64上的ILP32。 - user2467198
那么像Java/C#这样的语言比C/C++更有可能获得这种2倍效果(特别是如果您不使用大量指针),对吗? - David says Reinstate Monica
@DavidGrinberg 这也取决于数据。比如,一个大部分数据都在本地数组中的程序,如 int[]double[],不会有太大变化。然而,一个处理大量小对象的程序将需要更多的内存。 - glglgl
2
由于压缩的oops,使用小于 ~4GiB堆的Java程序可能会保持不变。 - Tavian Barnes
@TavianBarnes 谢谢,这对我来说是新的。那么在64位下工作应该不会有问题... - glglgl
1
@TavianBarnes 实际上,通过使用8或26字节的对象对齐方式,JVM可以使用32位引用来寻址64 GB。 - Peter Lawrey

27

内存占用增加有几个原因。但64位与32位的开销取决于应用程序。

  • 主要原因是在代码中使用了大量指针。但是,在编译为64位并在64位操作系统上运行的代码中动态分配的数组将与在32位系统上分配的数组相同。只有数组的地址更大,内容大小将相同(除非类型大小发生改变 - 但是这不应该发生,并且应该得到很好的记录)。

  • 另一个足迹增加是由于内存对齐。在64位模式下,对齐需要考虑64位地址,因此应该会增加一些开销。

  • 可能代码大小会增加。在某些架构中,64位ISA可能略微大一些。此外,现在您必须调用64位地址。

  • 在运行时,寄存器更大(64位),因此如果使用许多数字类型,则编译器也可以将它们放置在寄存器中,因此这并不一定意味着RAM占用会增加。如果未将其存储到64b寄存器中,则使用double变量可能会导致内存占用增加。

  • 当使用像Java,.NET这样的JIT编译语言时,64位代码的占用量可能会更大,因为运行时环境将通过指针使用,隐藏控制结构等产生额外开销。

但是,没有描述64位内存占用开销的魔术数字。这需要从一个应用程序测量到另一个。从我看到的情况来看,与32位相比,在64位上运行的应用程序的占用量最多增加了20%。但是,这纯粹是基于我遇到的应用程序,并且我主要使用C和C++。


跳转通常是相对于32位的。您无法使用单个jmp指令跳转到绝对64位地址。 - phuclv
唯一具有64位立即数的指令是movabs,因此您也无法在64位立即数地址处调用函数。 - phuclv
我相信你可以调用64位绝对地址。在这里检查:http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf - VAndrei
唯一可以使用完整64位位移的指令是使用MOV,AL,AX,EAX或RAX(但不是其他寄存器)加载或存储到绝对64位地址,因此您也不能使用64位位移进行调用。 - phuclv
趣闻轶事:我的.NET应用程序在空闲时使用的RAM比64位进程多约30%,在处理数据时(峰值内存使用)则多50%。 - Roman Starkov
显示剩余3条评论

0

我认为可能有另一个原因,这个原因可以追溯到变量需要存储在内存的64位边界上,地址为...xxxxx000,以便可以一次读取。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接