2009-09-21 17 views
5

Nasza aplikacja kończy się niepowodzeniem na jednym komputerze użytkownika pod numerem ERROR_NOT_ENOUGH_MEMORY ("Brak wystarczającej ilości pamięci do przetworzenia tego polecenia").Rozwiązywanie problemów ERROR_NOT_ENOUGH_MEMORY

Błąd najwyraźniej powstaje gdzieś głęboko w ramach Delphi VCL, z którego korzystamy, więc nie jestem pewien, która funkcja Windows API jest odpowiedzialna.

Czy pamięć jest problemem? Wywołanie GlobalMemoryStatus daje następujące informacje:

  • dwTotalPhys - 1063150000 (~ 1 D)
  • dwAvailPhys - 26735000 (~ 27 MB)
  • dwAvailPage - 1489000000 (około 1,4 GB)

Wydaje mi się dziwne, że system Windows pozwoliłby na tak niską dostępną pamięć fizyczną, gdy dostępna jest tak duża ilość miejsca w pliku stronicowania, ale nie wiem wystarczająco dużo o zarządzaniu pamięcią wirtualną systemu Windows, aby wiedzieć, czy jest to normalne czy nie. . Czy to jest?

Jeśli nie ma pamięci, to jaki limit zasobów jest wysyłany? Z tego, co czytam online, wynika, że ​​ERROR_NOT_ENOUGH_MEMORY może być skutkiem zastosowania jednego z kilku ograniczeń (obiekty GDI, obiekty USER, uchwyty itp.) I niekoniecznie pamięci. Czy istnieje pełna lista ograniczeń ograniczających działanie systemu Windows? Czy jest jakiś sposób, aby dowiedzieć się, który limit został trafiony? Próbowałem Google, ale nie mogłem znaleźć żadnego systematycznego przeglądu.

+0

GDI to mój pierwszy port zawinięcia. Chociaż to dziwne, że dzieje się to tylko na komputerze jednego użytkownika, to tam zaczynałem. Może to być również liczba używanych uchwytów itp. Powodzenia! –

Odpowiedz

3

Sprawca w tym przypadku był CreateCompatibleBitmap. Wygląda na to, że system Windows może egzekwować dość restrykcyjne ograniczenia systemowe dla pamięci dostępnej dla map bitowych zależnych od urządzenia (patrz np. this mailing list discussion), nawet jeśli twój system ma dużo pamięci i mnóstwo zasobów GDI. (Te ogólnosystemowe limity są najwyraźniej spowodowane tym, że system Windows może przydzielać zależne od urządzenia mapy bitowe w pamięci karty graficznej).

Rozwiązaniem jest po prostu użycie map bitowych niezależnych od urządzenia (DIB) (chociaż mogą one nie zapewniać tak dobrej jakości wydajność). This KB article opisuje, jak wybrać optymalny format DIB dla urządzenia.

Innymi kandydatami do limitów zasobów (z odpowiedziami innych ludzi i moje własne badania):

  • zasobów GDI (z tej odpowiedzi) - łatwo sprawdzane z GDIView
  • fragmentacji pamięci wirtualnej (z tej odpowiedzi)
  • pulpitu sterty - patrz here lub here
3

Częściej przyczyną tego błędu niż którykolwiek z wymienionych elementów jest fragmentacja wirtualnej przestrzeni pamięci. Jest to sytuacja, w której, podczas gdy całkowita wolna pamięć jest całkiem rozsądna, wolna przestrzeń jest pofragmentowana z różnymi bitami aktualnie przydzielanej wirtualnej przestrzeni pamięci. W związku z tym można uzyskać błąd braku pamięci, gdy żądanie pamięci nie może zostać zaspokojone przez pojedynczy ciągły blok, mimo że jest on w zupełności wolny.

+0

To powinno być dość łatwe do sprawdzenia przez wypróbowanie tego samego ze świeżego restartu. Można by sądzić, że spróbowaliby tego zanim napisali to jako pytanie na SO (ale głupie rzeczy się wydarzyły ...) –

+0

@ T.E.D. : Ponowne uruchomienie nie jest bardziej skuteczne niż po prostu zabicie procesu błędu i ponowna próba. Każdy proces ma swoją własną świeżą przestrzeń pamięci wirtualnej, gdy jest tworzona po raz pierwszy. Problem zwykle pojawia się naturalnie w długiej aplikacji lub szybko, gdzie jest mieszanka dużych i małych porcji pamięci przydzielanych i zwalnianych dość szybko, z różnych okresów życia. Zwykle jest to wskaźnik, że część kodu powinna przechowywać listę buforów do ponownego wykorzystania, zamiast stale przydzielać i zwalniać pamięć. – AnthonyWJones

+0

Używanie FastMM w Delphi lepiej zapobiega fragmentacji pamięci wirtualnej. –

4

Sprawdź wszystkie możliwości.

Problemy z GDI można monitorować za pomocą bezpłatnego narzędzia GDIView. Jest to pojedynczy plik, który użytkownicy mogą uruchomić bez instalatora.

Zainstaluj również urządzenie ProcessExplorer na odpowiedniej maszynie.

Jeśli nie masz dostępu do urządzenia, poproś użytkownika o wykonanie zrzutów ekranu stanu monitorowanego przez aplikacje. Bardzo prawdopodobne, to da ci jakąś wskazówkę.

+0

GDIView podaje interesujące imponujące szczegóły dotyczące "obiektów GDI". – Wolf

0

Moja odpowiedź może być trochę późno, ale od mojego zmarłego e xperience z tym samym problemem, wykonując wszystkie testy, przechodząc krok po kroku, tworząc DC, zwalniając go, używając DIBSection zamiast CompatibleBitmap, używając narzędzi GDI/Memory wycieku, itp.

W końcu (LOL) znalazłem to :

Zmieniłem priorytet tych dwóch połączeń, wtedy cały problem został naprawiony.

DeleteDC(hdc);  //do it first (always before deleting objects) 
DeleteObject(obj); 
Powiązane problemy