2013-08-16 17 views
17

Otrzymuję problem z pamięcią, której nie mogę zrozumieć.Python 32-bitowe limity pamięci na 64-bitowe okna

Jestem na komputerze Windows 7 z 64-bitową pamięcią i uruchomieniem 32-bitowego programu python.

Programy odczytują 5118 zipowanych plików numpy (npz). systemu Windows informuje, że pliki zajmują 1,98 GB na dysku

Każdy plik NPZ zawiera dwa elementy danych: „arr_0” jest typu np.float32 i „arr_1” jest typu np.uint8

Skrypt Pythona odczytuje każdy plik dołącza swoje dane do dwóch list, a następnie zamyka plik.

Około pliku 4284/5118 program rzuca MemoryException

Jednak menedżer zadań, mówi, że użycie pamięci python.exe * 32, gdy wystąpi błąd jest 1,854,848K ~ = 1,8 GB. Znacznie mniej niż mój limit 8 GB lub przypuszczalny limit 4 GB programu 32-bitowego.

W programie przechwytywam błąd pamięci i raportuje: Każda lista ma długość 4285. Pierwsza lista zawiera łącznie 1 928 588 480 danych float32 ~ ~ 229,9 MB. Druga lista zawiera 12 342 96,27 272 uint8 ~ = 1 471,3 MB danych.

Wszystko wydaje się być sprawdzane. Z wyjątkiem części, w której pojawia się błąd pamięci. Absolutnie mam więcej pamięci, a plik, na którym się zawiesza, ma ~ 800 KB, więc nie zawiedzie przy odczycie ogromnego pliku.

Ponadto plik nie jest uszkodzony. Mogę to przeczytać dobrze, jeśli wcześniej nie zużyję całej tej pamięci.

Aby wszystko było bardziej zagmatwane, wszystko to działa dobrze na moim komputerze z systemem Linux (chociaż ma 16 GB pamięci w przeciwieństwie do 8 GB na moim komputerze z systemem Windows), ale nadal nie wydaje się być pamięci RAM komputera, który powoduje ten problem.

Dlaczego Python zgłasza błąd pamięci, kiedy oczekuję, że będzie w stanie przydzielić kolejne 2 GB danych?

+0

Ilość fizycznej pamięci RAM, którą masz, jest nieistotna. W systemie Windows zawsze masz zamiany, czy tego chcesz, czy nie. – abarnert

+0

Kiedy to działa na twoim komputerze z Linuksem ... czy to samo dotyczy też 32-bitowego Pythona? – abarnert

+1

czy możesz opublikować kod, którego używasz do załadowania pliku '.npz'? jeśli użyjesz 'np.load (file, mmap_mode = 'r +')' to użyje znacznie mniej pamięci, ponieważ z tym argumentem otworzysz ['tablicę z mapowaną pamięcią'] (http://docs.scipy.org /doc/numpy/reference/generated/numpy.load.html) ... –

Odpowiedz

33

Nie wiem, dlaczego uważasz, że Twój proces powinien mieć dostęp do 4 GB. Według Memory Limits for Windows Releases w MSDN, w 64-bitowym systemie Windows 7, domyślny proces 32-bitowy pobiera 2 GB. * Dokładnie tam, gdzie kończy się.

Czy istnieje sposób obejścia tego?

Cóż, można utworzyć niestandardową kompilację 32-bitowego Pythona, która używa flagi IMAGE_FILE_LARGE_ADDRESS_AWARE i odbudować numpy i wszystkie inne moduły rozszerzeń. Nie mogę obiecać, że cały odpowiedni kod naprawdę jest bezpieczny do uruchomienia z flagą z dużym adresem; istnieje duża szansa, ale jeśli ktoś już tego nie zrobił i nie przetestował, "najlepsza szansa" jest najlepsza, o czym każdy może wiedzieć.

Lub, bardziej oczywiście, po prostu użyj 64-bitowego Pythona.


Ilość fizycznej pamięci RAM jest zupełnie nieistotna. Wydaje się, że masz "limit 8 GB" z 8 GB pamięci RAM, ale tak nie działa.Twój system zabiera całą pamięć RAM plus dowolne miejsce do wymiany, które potrzebuje i dzieli je między aplikacje; aplikacja może uzyskać 20 GB pamięci wirtualnej bez otrzymania błędu pamięci nawet na komputerze o pojemności 8 GB. A w międzyczasie 32-bitowa aplikacja nie ma dostępu do więcej niż 4 GB, a system operacyjny zużyje trochę tej przestrzeni adresowej (w połowie domyślnie w systemie Windows), więc możesz uzyskać tylko 2 GB nawet na 8 GB to nie działa nic innego. (Nie, że jest to możliwe, aby zawsze być „nie działa nic innego” na nowoczesnym systemie operacyjnym, ale wiesz co mam na myśli.)


Więc dlaczego to działa na swoim Linuksie?

Ponieważ twoje urządzenie Linux-a jest skonfigurowane tak, aby zapewniało procesom 32-bitowym 3,5 GB wirtualnej przestrzeni adresowej lub 3,99 GB, lub ... Cóż, nie mogę podać dokładnej liczby, ale każdej dystrybucji, którą widziałem dla wielu lata zostało skonfigurowane na co najmniej 3,25 GB.


* Należy również pamiętać, że nawet nie można uzyskać pełnego 2 GB danych; twój program. Większość tego, co system operacyjny i jego sterowniki udostępniają Twojemu kodowi, znajduje się w drugiej połowie, ale niektóre bity znajdują się w twojej połówce, wraz z każdą ładowaną biblioteką DLL i dowolną przestrzenią, jakiej potrzebują, i wieloma innymi rzeczami. Nie sumuje się za dużo, ale nie jest zero.

+0

Naprawdę nie musisz kompilować exe w oknach, 'IMAGE_FILE_LARGE_ADDRESS_AWARE' jest po prostu flagą w nagłówku obrazu (nie, że będzie to oficjalnie obsługiwane, ale hej nie oceniamy;)). Również biblioteki dll nie mają w tej sprawie nic do powiedzenia, więc nie trzeba ich zmieniać w żaden sposób. – Voo

+0

@Voo: Ale cały twój kod, łącznie z twoimi bibliotekami DLL, musi być bezpieczny dla _use_ z włączoną flagą. Jeśli, powiedzmy, Python i jego standardowe moduły rozszerzeń sprawdzają w czasie kompilacji, czy chcesz obsługiwać duży adres i generować inny kod w różnych przypadkach, musisz przebudować wszystko, a nie tylko exe. Jeśli są one ogólnie bezpieczne dla wielu adresów, nie musisz nic robić. A jeśli nigdy nie są bezpieczne dla wielu adresów, odbudowa nie pomoże. Nie znam żadnej dokumentacji, która mówi, która z tych trzech rzeczy jest ... – abarnert

+0

Prawda, chociaż jedynym powodem, dla którego kod zakończy się niepowodzeniem z IMAGE_FILE_LARGE_ADDRESS_AWARE, jest to, że jest zepsuty na początku (matematyka z podpisaną wskazówką) lub robi głupie sztuczki z wysoki porządek wskazówek. Jestem bardzo zaskoczony, że pyton robi to - gdzie dokładnie w kodzie? (GC Przypuszczam, że jest to jedyny powód, dla którego może to być przydatne) Chciałbym na to popatrzeć. – Voo