Knuth最近反对64 位系统,他说对于适合 4 GB 内存的程序,“它们实际上丢弃了一半的缓存”,因为指针是 32 位系统上的两倍。
我的问题是:可以通过在 64 位机器上安装 32 位操作系统来避免这个问题吗?是否有任何带宽密集型基准可以证明这种情况下的优势?
带宽在这里并不是真正的正确术语。Knuth 真正谈论的是数据密度,因为它与缓存占用有关。假设你有一个 16KB 的 L1 数据缓存:如果你纯粹存储指针,你可以存储 2^14/2^2 = 2^12 = 4096 个 32 位指针,但只能存储 2048 个 64 位指针。如果您的应用程序的性能取决于能够跟踪超过 2K 的不同缓冲区,那么您可能会看到 32 位地址空间的真正性能优势。然而,大多数实际代码并非如此,缓存系统的真正性能优势通常来自能够缓存常见的整数和浮点数据结构,而不是大量的指针。如果您的工作集不是大量指针,则 64 位的缺点可以忽略不计,而如果您使用“
答案是:是的,在一定程度上可以,尽管性能差异不太可能很大。
任何测试这个的基准都必须做大量的指针解析,这将很难从噪音中分离出来。设计一个不会优化的基准是困难的。 这篇关于有缺陷的 Java 基准测试的文章是有人在回答另一个问题时发布的,但其中描述的许多原则都适用于此。
我不认为 Knuth 反对 64 位系统。他只是说在内存小于 4GB 的系统上使用 64 位指针是愚蠢的(至少如果你有很多指针,比如双链表中的指针)。我不能说我同意他的观点,这里有 3 种不同的方式可以采取。假设您有一个支持 64 位的 CPU,它也可以像某些 Intel Core Duo 一样在 32 位模式下运行。
1 - 一切都是 32 位的,操作系统、APPZ 等等。所以你有 32 位指针,但你不能使用 64 位模式下可用的额外寄存器/指令。
2 - 一切都是 64 位的,操作系统、APPZ 等等。所以你有 64 位指针,你可以使用 64 位模式下可用的额外寄存器/指令。但是由于您的内存少于 4GB,因此使用 64 位指针似乎很愚蠢。但是,是吗?
3 - 操作系统是 64 位的,有趣的是,操作系统确保所有代码/数据指针都在 0x00000000 - 0xFFFFFFFF 范围内(虚拟内存!!!)。ABI 以一种非常奇怪的方式运行,所有保存在内存/文件中的代码/数据指针都是 32 位宽的,但它们作为零扩展加载到 64 位寄存器中。如果有要跳转的代码位置,编译器/ABI 会进行必要的修复并执行实际的 64 位跳转。这样,指针是 32 位的,但 APPZ 可以是 64 位的,这意味着它们可以使用 64 位的寄存器和指令。我认为这个过程有点像 thunking ;-P
我的结论是::
第三个选项对我来说似乎可行,但这不是一个容易的问题。理论上它可以工作,但我认为它不可行。而且我还认为他的引用“当这样的指针值出现在结构中时,它们不仅浪费了一半的内存,而且还有效地丢弃了一半的缓存。” 被夸大了……
我在某处看到最好的组合(在 x86 CPU 上)是使用 64 位操作系统和 32 位应用程序。
使用 64 位操作系统,您将获得:
使用 32 位应用程序,您将获得:
缺点:
令人惊讶的是,切换模式时似乎没有任何开销。我想无论用户空间的位数如何,从用户空间中断到内核的成本都是一样的。
当然,有些应用程序可以从大地址空间中受益。但对于其他一切,您可以通过保持 32 位获得额外 5% 的性能。
不,我不在乎这个小小的加速。但在 64 位 KUbuntu 机器上运行 32 位 FireFox 并没有“冒犯”我(就像我在一些论坛上看到的那样)