64 位窗口上的 Python 32 位内存限制
Posted
技术标签:
【中文标题】64 位窗口上的 Python 32 位内存限制【英文标题】:Python 32-bit memory limits on 64bit windows 【发布时间】:2013-08-19 10:10:30 【问题描述】:我遇到了一个我似乎无法理解的内存问题。
我在一台具有 8GB 内存并运行 32 位 python 程序的 Windows 7 64 位机器上。
程序读取 5,118 个压缩的 numpy 文件 (npz)。 Windows 报告文件在磁盘上占用了 1.98 GB
每个 npz 文件包含两条数据: 'arr_0' 的类型为 np.float32 和 'arr_1' 的类型是 np.uint8
python 脚本读取每个文件并将其数据附加到两个列表中,然后关闭文件。
在文件 4284/5118 附近,程序抛出 MemoryException
但是任务管理器说python.exe *32出错时的内存使用量是1,854,848K ~= 1.8GB。远低于我的 8 GB 限制,或者 32 位程序的 4GB 限制。
在程序中我发现内存错误并报告: 每个列表的长度为 4285。 第一个列表总共包含 1,928,588,480 个 float32 的 ~= 229.9 MB 数据。 第二个列表包含 12,342,966,272 个 uint8 的 ~= 1,471.3MB 数据。
所以,一切似乎都在检查。除了我得到内存错误的部分。 我绝对有更多的内存,它崩溃的文件是~800KB,所以它在读取一个大文件时不会失败。
此外,文件没有损坏。如果我不事先用完所有内存,我可以很好地阅读它。
为了让事情变得更加混乱,所有这些似乎在我的 Linux 机器上都可以正常工作(虽然它确实有 16GB 的内存,而在我的 Windows 机器上是 8GB),但它似乎不是机器的导致此问题的 RAM。
当我期望它应该能够分配另外 2GB 的数据时,为什么 Python 会抛出内存错误?
【问题讨论】:
您拥有的物理 RAM 数量无关紧要。在 Windows 上,无论您是否愿意,您总是可以进行交换。 你能发布你用来加载.npz
文件的代码吗?如果您使用np.load(file, mmap_mode='r+')
,它将使用更少的内存,因为使用此参数您将打开一个memory-mapped array
...
问题不在于 python 本身,而在于 numpy 和 scipy,需要 64 位 fortran 编译器。如果我没记错的话,唯一现有的来自英特尔,而且不是免费的。我知道您可以使用WinPyton,所以这是可能的。不过,您必须使用不隶属于 python.org 的网站的非官方二进制文件。
@Erotemic:是什么让你觉得 32 位 Python 更稳定?如今,大多数核心开发人员都在 64 位 Unix 机器上。存在许多错误和性能问题,其中一个更改使 32 位变得更糟,几个月来没有人注意到,而在另一个方向上则很少。我可以理解有构建/工具链问题,但如果你真的认为 Python 本身在 64 位上不稳定,那你就大错特错了。
@J.Martinot-Lagarde:一年多以前,有两个问题。首先,gfortran 还没有准备好迎接 MinGW64 的黄金时间,但今天不是这样。它现在是完全受支持的平台之一,就像 MinGW32(以及本机 Win32、cygwin 和所有 *nixes)一样。另一部分——Christoph Gohkle 的 Win64 二进制 scipy 包可能有一些不明确的许可,这给任何想要分发使用它们的二进制包的人带来了问题——与许多人无关,尤其是那些不想使用“来自不隶属于 python.org 的网站的非官方二进制文件”。
【参考方案1】:
我不知道您为什么认为您的进程应该能够访问 4GB。根据 MSDN 上的Memory Limits for Windows Releases,在 64 位 Windows 7 上,默认的 32 位进程获得 2GB。* 这正是它耗尽的地方。
那么,有没有办法解决这个问题?
好吧,您可以使用 IMAGE_FILE_LARGE_ADDRESS_AWARE
标志自定义构建 32 位 Python,并重建 numpy
和所有其他扩展模块。我不能保证所有相关代码都可以安全地使用大地址感知标志运行。这是一个很好的机会,但除非有人已经做过并测试过,否则“一个很好的机会”是任何人都可能知道的最好的。
或者,更明显的是,改用 64 位 Python。
物理 RAM 的数量完全无关紧要。你似乎认为你有 具有 8GB RAM 的“8GB 限制”,但这不是它的工作原理。您的系统会占用您所有的 RAM 加上它需要的任何交换空间,并将其在应用程序之间进行划分;即使在 8GB 的机器上,应用程序也可能能够获得 20GB 的虚拟内存而不会出现内存错误。同时,一个 32 位应用程序无法访问超过 4GB 的空间,并且操作系统会占用一些地址空间(在 Windows 上默认为一半),因此即使在 8GB 机器上也只能获得 2GB那没有运行其他任何东西。 (并不是说在现代操作系统上“不运行任何其他东西”是可能的,但你知道我的意思。)
那么,为什么这可以在你的 linux 机器上工作?
因为你的 linux 机器被配置为给 32 位进程 3.5GB 的虚拟地址空间,或者 3.99GB,或者……嗯,我不能告诉你确切的数字,但是我多年来见过的每个发行版已配置为至少 3.25GB。
* 另请注意,您甚至没有真正获得完整的 2GB 数据;你的程序。操作系统及其驱动程序使您的代码可以访问的大部分内容位于另一半,但有些位位于您的那一半,以及您加载的每个 DLL 和它们需要的任何空间,以及其他各种东西。加起来不算多,但也不是零。
【讨论】:
您实际上不必在 Windows 上编译 exe,IMAGE_FILE_LARGE_ADDRESS_AWARE
只是图像标题中的一个标志(并不是说这会得到官方支持,但是我们不判断; ))。 dll 在这件事上也没有发言权,因此无论如何都不必更改。
@Voo:但是您的所有代码,包括您的 DLL,都必须在打开标志的情况下使用是安全的。例如,如果 Python 及其标准扩展模块在构建时检查您是否需要大地址感知支持并在不同情况下生成不同的代码,那么您将需要重新构建所有内容,而不仅仅是 exe。如果它们总是大地址安全,那么你不需要做任何事情。如果它们从不大地址安全,那么重建将无济于事。我不知道有任何文档可以告诉您它是这三个中的哪一个……
是的,尽管代码将因 IMAGE_FILE_LARGE_ADDRESS_AWARE 失败的唯一原因是它是否以(带符号的指针数学)开头被破坏或使用指针的高位进行愚蠢的把戏。我很惊讶python会做这些事情——代码到底在哪里? (我认为 GC,这几乎是这可能有用的唯一原因)很想看看。
@Voo:我完全不知道 Python 或 OP 所依赖的任何 Python 模块是否会做这样的事情。我认为这不太可能,但我不能保证。显然,它不是用开箱即用的IMAGE_FILE_LARGE_ADDRESS_AWARE
构建的。我的猜测是,原因是到目前为止,没有一个开发人员发现它值得测试和/或清理源代码,因为如果他们真的需要超过 2GB 的空间,他们只会使用 64 位构建。但这只是一个猜测,这就是为什么我的回答说它很有可能会起作用,但我不能保证。
是的,但是如果没有python依赖的编译器开关,那么与仅更改标题中的一个位相比,重建python的所有工作将完全没有任何作用,这是我的观点。而且我真的看不出python如何使用任何依赖于未使用的高位位的东西——毕竟*nix通常不提供这样的保证并且python在那里运行良好。以上是关于64 位窗口上的 Python 32 位内存限制的主要内容,如果未能解决你的问题,请参考以下文章
64 位 Windows 上的 32 位 JVM 最大内存大小没有预期的那么大
Windows 7(64 位)上的 Python 3.7 64 位:CSV - 字段大于字段限制(131072)[重复]