Подтвердить что ты не робот

32-разрядные ограничения памяти Python на 64-битных окнах

У меня проблема с памятью, которую я не могу понять.

Я нахожусь на 64-битной машине Windows с 8 ГБ памяти и запускаю 32-битную программу python.

Программы читают 5,118 зашифрованных numpy файлов (npz). Windows сообщает, что файлы занимают 1,98 ГБ на диске

Каждый файл npz содержит две части данных: 'arr_0' имеет тип np.float32 и 'arr_1' имеет тип np.uint8

Python script читает каждый файл, добавляет свои данные в два списка, а затем закрывает файл.

Вокруг файла 4284/5118 программа выдает исключение MemoryException

Однако диспетчер задач говорит, что использование памяти python.exe * 32 при возникновении ошибки составляет 1,854,848K ~ = 1,8 ГБ. Гораздо меньше, чем мой 8-гигабайтный лимит, или предполагаемый 4-гигабайтный предел 32-битной программы.

В программе я улавливаю ошибку памяти, и она сообщает: Каждый список имеет длину 4285. Первый список содержит в общей сложности 1,928,588,480 float32 ~ = 229,9 МБ данных. Второй список содержит 12 342 966 272 uint8 ~ = 1,471.3MB данных.

Итак, все, кажется, проверяется. За исключением части, где я получаю ошибку памяти. У меня больше памяти, и файл, с которым он падает, составляет ~ 800 КБ, поэтому он не пропустил чтение огромного файла.

Кроме того, файл не поврежден. Я могу прочитать его просто отлично, если я не буду использовать всю эту память заранее.

Чтобы сделать вещи более запутанными, все это, кажется, отлично работает на моей машине Linux (хотя у нее есть 16 ГБ памяти, а не 8 ГБ на моей Windows-машине), но, тем не менее, это, похоже, не машина ОЗУ, которая вызывает эту проблему.

Почему Python бросает ошибку памяти, когда я ожидаю, что он сможет выделить еще 2 ГБ данных?

4b9b3361

Ответ 1

Я не знаю, почему вы думаете, что ваш процесс должен иметь доступ к 4 ГБ. Согласно Ограничениям памяти для выпуска Windows в MSDN, в 64-разрядной версии Windows 7, 32-разрядный процесс по умолчанию получает 2 ГБ. * Именно так он заканчивается.

Итак, есть ли способ обойти это?

Ну, вы можете создать пользовательскую сборку из 32-разрядного Python, которая использует флаг IMAGE_FILE_LARGE_ADDRESS_AWARE, и перестроить numpy и все ваши другие модули расширения. Я не могу обещать, что весь соответствующий код действительно безопасен для работы с флагом с большим адресом; есть хороший шанс, но если кто-то уже это сделал и не протестировал, "хороший шанс" - это лучший, кто может знать.

Или, что более очевидно, просто используйте 64-битный Python.


Объем физической ОЗУ не имеет значения. Вы, кажется, думаете, что у вас есть "ограничение 8 ГБ" с 8 ГБ ОЗУ, но это не так, как это работает. Ваша система использует всю вашу оперативную память, а также любое пространство подкачки, в котором она нуждается, и разделяет ее между приложениями; приложение может получить 20 ГБ виртуальной памяти, не получая ошибку памяти даже на машине 8 ГБ. Между тем, 32-разрядное приложение не имеет доступа к более чем 4 ГБ, и ОС будет использовать некоторые из этих адресных пространств (половина из них по умолчанию в Windows), поэтому вы можете получить только 2 ГБ даже на машине с 8 ГБ что ничего не работает. (Не для того, чтобы когда-либо быть "не работающим ничего" на современной ОС, но вы знаете, что я имею в виду.)


Итак, почему это работает в вашей Linux-коробке?

Поскольку ваш Linux-модуль настроен на предоставление 32-разрядных процессов на 3,5 ГБ виртуального адресного пространства, или 3,99 ГБ, или... Ну, я не могу сказать вам точный номер, но каждый дистрибутив, который я видел много лет был настроен как минимум на 3,25 ГБ.


* Также обратите внимание, что вы даже не получаете полные 2 ГБ данных; вашей программы. Большая часть того, что ОС и его драйверы делают доступными для вашего кода, находится в другой половине, но некоторые биты сидят в вашей половине, вместе с каждой загружаемой DLL и любым необходимым пространством и другими вещами. Это не слишком много, но это не ноль.