OutOfMemory przy wolnej pamieci

0

Mój problem dotyczy tablic dynamicznych i wydaje się prosty: przy wykonywaniu SetLength() pojawia mi się czasami EOutOfMemory.
Błąd z całą pewnością nie jest spowodowany brakiem pamięci, bo tablica liczy max.80MB, a dostępne jest ok. 1GB. Pojawianie się błędu jest rzadkie i ma charkter losowy, co pracę nad nim czyni niemal beznadziejną.

Czy miałby ktoś jakieś sugestie na temat możliwych przyczyn takich objawów? Podejrzewałem jakieś wycieki i związane z tym przymazanie pamięci, ale niczego takiego nie zauważyłem.

0

Pytanie ile faktycznie tych tablic jest w pamięci. Poza tym najczęstszą przyczyną EOutOfMemory jest zapętlenie.

0

Tak jak napisał adf88, do tego nie podałeś, co przechowujesz w tablicach dynamicznych. Jeśli trzymasz tam wskaźniki do jakichś struktur - błąd może być spowodowany niewłaściwym ich tworzeniem/zwalnianiem
Generalnie SetLength tworzy kopię tablicy, więc maże ostro po pamięci. Jeśli masz gdzie indziej jakiś obszar "wątpliwej jakości" a nowa tablica w niego trafi - masz objawy wypisz wymaluj takie jak u Ciebie. Słowem - na bank błąd dostajesz nie dlatego, że zmieniasz rozmiar tablicy, tylko dlatego, że gdzieś wcześniej zniszczyłeś sobie pamięć.

Jeśli korzystasz z D2005 wzwyż - ustaw w projekcie ReportMemoryLeaksOnShutdown := true (najlepiej w źródłach samego projektu, od razu na początku). Możesz też podłączyć FastMM4 (dowolna wersja Delphi) i będziesz miał wyciek na widelcu z bardziej szczegółowymi danymi. Podobno EurekaLog też to potrafi, ale ja się obywałem dwoma poprzednimi opcjami.

0

Tablicę, o której pisałem (80MB) zawsze mam co najwyżej jedną w jedym uruchomieniu programu. Tymczasowo przechwuję w niej potrzebne dane (o różnej objętości) i usuwam. Oprócz tego tworzę jednak i usuwam mnóstwo tablic (po ok 5MB i kilka mniejszych) w wątkach, których wykonuję sekwencyjnie około 150 po 4 na raz (co ustawiam semaforem). W żadnej tablicy nie przechowuję wskaźników.

Utworzyłem werscję testową programu, która wykonuje cały proces wczytywania danych w pętli - po 10 tym obiegu mam mam 'OutOfMemory', pomimo, że nawet szczytowe zużycie pamięci nie wyniosło 1GB (na 3.2 dostępnych). Na ironię zakrawa fakt, że problemy te pojawiają się po przeniesieniu programu na szybką maszynę (ok. 4X3600). Przy wolniejszym komputerze (2x1800MHz) wszystko działa dobrze!

0

A ustawienia pamięci wirtualnej masz takie same?
Imo systemowe odśmiecanie pamięci nie działa natychmiast, ale wskazanie konkretnej przyczyny Twoich kłopotów to zadanie dla wróżki albo kogoś, komu by się chciało męczyć z analizą 150 wątków :)

0

a fragmentacja pamięci? każdy zaalokowany obszar pamieci musi być ciągły; jesli tworzysz i zwalniasz dużo tablic różnej wielkości, to pamięć robi się pofragmentowana i prawdopodobieństwo nieznalezienia ciągłego bloku o jakiejśtam wielkości wzrasta.

0

A sposób alokacji?

0

Wielkość pamięci wirtualnej wynosi 2.5GB, więc nie gra roli.
Sądzę, że Delphi powinno radzić sobie z fragmentacją pamięci.
Stosuję SetLenght(), a więc ogólnie rzecz biorąc alokację dynamiczną - trudno mi powiedzieć dokładnie jak manipuluje ona pamięcią (być może rzeczywiscie potrzbuje ciągłego obszaru).

Ponieważ na wolniejszym koputerze wszystko chodziło, więc na razie stosuję półśrodek w postaci opóźnienia uruchuamiania wątków - 10ms. Przypuszalnie czas ten wystarcza na uporządkowanie pamięci przed następną alokacją ...

Testy dają rezultaty pozytywne, ale istota problemu pozostaje nie rozwikłana :)

0

Delphi nie ma prawa radzić sobie z fragmentacją pamięci, to nie język z sensownym GC w stylu Common Lispu. Masa wątków alokujących masę małych buforów na wspólnej stercie robi straszny burdel - sterta gwałtownie rośnie a wolne bloki są zbyt małe aby zaalokować większe żądania. Opóźnianie wątków daje w tym wypadku pewne rozwarstwienie sterty zmniejszając fragmentację... Jak dla mnie to dla każdego wątku bądź puli wątków powinieneś utworzyć oddzielną stertę i ew. dodatkowo zamiast stałych pointerów używać uchwytów do zasobów na stercie, pozwala to na użycie funkcji do porządkowania sterty. Inna sprawa - czy faktycznie potrzebujesz tak wielu wątków? Nie możesz rozdzielić zadań na powiedzmy 4 wątki? Taka masa 'równoległych' wątków spowalnia tylko program i cały system i zjada dodatkowe zasoby.

Aktualnie tylko zmniejszyłeś szansę wysypanie się programu, zamiotłeś śmieci pod dywan...

// edit: czyli jednak natywne tablice dynamiczne Delphi, w takim razie trudno mi coś konkretnego powiedzieć... ręczne zarządzanie stertą już tutaj tak wiele nie da.

0

Deus, dzięki za rzeczowe sugestie.
Coś mi się wydaje, że będę musiał gruntownie przebudować program ...

0
deus napisał(a)

Jak dla mnie to dla każdego wątku bądź puli wątków powinieneś utworzyć oddzielną stertę

A jak to się robi?

0

WINAPI posiada taką funkcję jak HeapCreate + cały zestaw funkcji do zarządzania stertą.

0

Skorzystaj z EurekaLog (w wersji Trial, wskaże ci wszystko, błędy, wycieki).

Pamiętaj jednak, aby po naprawieniu błędu usunąć EurekeLog z "programu", gdyż po 30dniach twoja aplikacja przestanie się uruchamiać.

Jak byś nie wiedział, jak skorzystać - pytaj.

1 użytkowników online, w tym zalogowanych: 0, gości: 1