2012-04-05 26 views
6

Buduję aplikację delphi, która wykonuje symulację naukową. Rośnie w złożoności & teraz składa się z wielu jednostek i form.Delphi: Jak znaleźć i naprawić błąd EOutOfMemory?

Zaczynam otrzymywać błędy EOutOFMemory przy każdym uruchomieniu. Wydaje się, że dzieje się to podczas lub zaraz po tym, jak używam Tablicy wariantów tymczasowo w ramach funkcji. Ryzykując zadając naprawdę głupie pytanie, czy "tablica wariantów" prosi o kłopoty? (Mógłbym konwertować wszystko na string, ale tablica wariantów w zasadzie oszczędza wiele rzeczy kłamliwych).

przestępstwa użycie tablica może być:

Function TProject.GetCurrentProjParamsAsArray(LProjectName, LProjectType : ShortString): ArrayOfVariant; 
Var 
    ArrayIndex : Word; 
begin 
    SetLength (Result,54); 
    ArrayIndex := 0; 
    Result [ArrayIndex] := LProjectName;  Inc(ArrayIndex); 
    Result [ArrayIndex] := LProjectType;  Inc(ArrayIndex);     // this structure makes it easier to add extra fields in the DB than hard coding the array index!! 
    Result [ArrayIndex] := FileTool.DateTimeForFileNames ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. SiteName   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. PostCode   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. MetFileNamePath  ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. SiteLat    ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. SiteLong   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. SiteAlt    ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. TZoneIndex   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. TZoneHours   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. TZoneMeridian  ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. Albedo    ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. ArrayTilt   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. ArrayAzimuth  ; Inc(ArrayIndex); 

w Menedżerze zadań - szczytowego zużycia pamięci jest 42MB, VM jest 31M i Dostaję ~ 90.000 stron usterek na metę. (na maszynie xp z 3 GB pamięci RAM)

Czy ktoś ma ogólne wskazówki dotyczące monitorowania użycia pamięci przez różne komponenty w mojej aplikacji? lub na śledzenie przyczyny tego błędu?

Niedawno przeszedłem od przechowywania głównych danych projektu jako CSV do korzystania z ADO DB, Jednocześnie zacząłem również używać typu danych Wariant, zamiast konwertować ciąg tekstowy i pojedynczy/podwójny cały czas.

Podążałem za różnymi wskazówkami dotyczącymi oszczędzania pamięci, które mogę znaleźć, gdzie, w praktyce, usunąłem Application.CreateForm (TProject, Project); wyciągi z .dpr i tworzenie ich dynamicznie. (z wyjątkiem przypadków, w których formularze są używane w większości przypadków). Generaly używam najmniejszą praktyczną typ danych (bajt, shortstring, etc) i zminimalizować wykorzystanie zmiennych & funkcji

wszelkie wskazówki bardzo mile widziane „publiczne”, Brian

+0

Spodziewasz się błędów strony. Nie martw się o to. Tablica 'Variant' nie brzmi zbyt źle. W końcu macie w tablicy tylko 54 elementy. 42 MB jest banalne. Niemal nie można powiedzieć, co się dzieje, biorąc pod uwagę tę informację. –

+0

Jak zdefiniowano 'ArrayOfVariant'? czy przechowujesz obiekty w tablicy, czy tylko proste typy? – RRUZ

+0

ArrayOfVariant jest zdefiniowany w oddzielnej jednostce użyteczności publicznej (ponieważ nie można przekazać "Array Of ...." między funkcjami, tj. ArrayOfVariant = Array of Variant, zawiera tylko wartości podwójne i wartościowe. – SolarBrian

Odpowiedz

2

Wątpię, aby kod, który wyświetlasz, był źródłem problemu. Prawdopodobnie jest to miejsce, w którym występuje objaw.

Jeśli podejrzewasz, że masz w rzeczywistości pewne podstawowe uszkodzenie niskiego poziomu, możesz spróbować włączyć tryb pełnego debugowania FastMM. Na przykład problemy takie jak ten, który napotykasz, mogą być spowodowane ogólnym uszkodzeniem sterty pamięci, a nie wyczerpaniem pamięci.

Jeśli nie masz uszkodzonego sterty, ale zamiast tego masz problem z prawdziwym brakiem pamięci, to znalezienie i rozwiązanie zazwyczaj wymaga odpowiedniego narzędzia, zwanego profilerem, takiego jak AQTime. Być może twój kod przydziału jest błędny w sposób, który możesz zrozumieć, jeśli po prostu debugujesz swój kod i odkrywasz, że próbujesz złapać nieuzasadnioną ilość pamięci, albo w jednym, albo w serii wywołań do funkcji przydzielania pamięci.

Jednak bez profilera, takiego jak pakiet jakości nexus lub AQTime lub innego podobnego narzędzia, będziesz w większości niewidomy. Twoja aplikacja po prostu nie działa, a kod zarządzania stosem informuje, że brakuje pamięci. Możliwe, że robisz coś gdzieś, co psuje ci kupę. Możliwe, że naprawdę przypisujesz zbyt dużo pamięci do 32-bitowego procesu. Możliwe, że twój komputer nie ma wystarczającej ilości pamięci rzeczywistej lub wirtualnej, lub że przydzielasz ogromną strukturę danych, której nie zrealizowałeś, nie jest praktyczna w twojej aplikacji.

+0

hmm AQTime spróbuje również, dzięki! – SolarBrian

+0

AQTime jest dość expesnive, w przeszłości próba bardzo mi pomogła. Istnieje również http://www.prodelphi.de/ – LaBracca

+0

Zamiast tego wypróbuj pakiet jakości nexus lub skorzystaj z darmowego pomysłu, użyj FastMM w trybie pełnego debugowania i użyj zrzutów sterty, aby określić, CO wykorzystuje twoją pamięć. –

10

EOutOfMemory występuje wtedy, gdy menedżer pamięci nie może znaleźć contigious blok pamięci dla danego wniosku o przydział. Więc albo 1) przydzielasz więcej pamięci niż się spodziewasz, 2) przecieka pamięć, którą udało ci się alokować, albo 3) fragmentację (niekoniecznie przeciekającą) pamięci, tak aby menedżer pamięci musiał przydzielać coraz więcej pamięci w czasie.

Po wystąpieniu wyjątku spójrz na stos wywołań. To doprowadzi cię do kodu, który nie może przydzielić pamięci. Aby uzyskać stos wywołań, uruchom aplikację w debugerze lub skorzystaj z systemu rejestrowania wyjątków, takiego jak MadExcept, EurekaLog, JCLExcept, itp.

+2

Fragmentacja jest prawdopodobnym wyjaśnieniem, ale wiadomo, która alokacja się nie powiedzie rzadko pomaga wyjaśnić fragmentację pamięci –

+0

Zwykle, ale czasami może, jeśli kod, który się zawiesza, jest ten sam kod, który się rozpada ... –

+0

Ach, ramy rejestrowania wyjątków brzmią bardzo dobrze, dzięki Wypróbuj to! – SolarBrian

2

Czy zainstalowałeś pełną wersję Menedżera pamięci FastMem? Może pomóc w wykryciu błędów w obsłudze pamięci. Sprawdź, czy coś przecieka.

Jeśli nie masz wycieku, masz dość ekstremalny problem z fragmentacją, musisz sobie z tym poradzić, utrzymując pulę obiektów, zamiast utrzymywać przydzielanie/zwalnianie ich.

+0

FastMM - spróbuję dzięki! – SolarBrian

2

Aby znaleźć przyczynę wyjątków OutOfMemory, należy przyjrzeć się wszystkim tworzeniu obiektów, a nie tylko temu, gdzie wyjątek został podniesiony.

Narzędzie trzeciej części, takie jak EurekaLog, może pokazać wszystkie obiekty utworzone w aplikacji i niepoprawnie usunięte. Możesz spróbować poprawić je za pomocą try finally finally z procedurą FreeAndNil.

+0

mmm, Ostatnio dodałem wiele funkcji Create/Free, aby zmniejszyć obciążenie pamięci przy użyciu rzadko używanych formularzy, więc może to być problem. dzięki! – SolarBrian

2

Brzmi jak wycieki pamięci.

zawsze dodać

{$IFDEF DEBUG} 
    ReportMemoryLeaksOnShutdown := DebugHook <> 0; 
    {$ENDIF} 

do pliku źródłowego projektu na mój debug buduje.

Daje to dobrą informację o tym, jak dobrze skompilowałem program.

+0

+1 @andy_k ale gdzie ją dodasz? – Mawg

Powiązane problemy