2016-09-19 20 views
6

Utworzono aplikację konsoli i ustaw opcję ReportMemoryLeaksOnShutdown: = True.Zgłaszanie wycieków pamięci podczas wyłączania za pomocą aplikacji konsolowej

Utworzono TStringList, ale go nie zwolniłem.

Po zakończeniu programu widzę przeciek pamięci na krótką sekundę, ale potem konsola zamyka się.

Próbowałem dodać ReadLn; do końca, ale pokazuje tylko puste okno konsoli, kiedy to robię, co ma sens.

Potrzebuję znaleźć sposób, aby wstrzymać wykonywanie po raport wycieku pamięci, ale przed zakończeniem programu.

Używam Delphi 10 Seattle.

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    System.Classes, 
    System.SysUtils; 

var 
    s : TStringList; 

begin 
    try 
    ReportMemoryLeaksOnShutdown := True; 
    s := TStringList.Create; 

    //ReadLn doesn't work here, which makes sense. 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    //I need to be able to pause the program somewhere after the end statement here. 
end. 
+6

Uruchom program w poprzednio otwartym oknie poleceń, a nie w IDE. –

+1

Możesz spróbować *** mojej jednostki "AutoConsole", zobacz tutaj: http://rvelthuis.blogspot.de/2016/07/new-velthuisautoconsole-unit.html. Po prostu dodaj go do programu konsoli. –

+0

Dodaj punkt przerwania na "system.end". –

Odpowiedz

6

Najłatwiej jest po prostu uruchomić aplikację w poprzednio otwartym oknie poleceń.

Jeśli nalegać na obejrzeniu raportu wyciek pamięci podczas pracy w IDE, wykonaj następujące czynności:

  • Zlokalizuj procedurę ShowMessage w GetMem.inc (linia 4856 w Seattle) Delphi 10
  • Zamieścić punkt przerwania w tej procedurze.

Alternatywnie, jak Sertac Akyuz powiedział, umieścić punkt załamania w end. jednostki system.

Możesz również przekierować raport wycieku pamięci do pliku. Pobierz pełną wersję FastMM z

https://sourceforge.net/projects/fastmm/

lub lepiej, dzięki Arioch zwanej dalej”, stąd:

https://github.com/pleriche/FastMM4

i ustaw potrzebne opcje w FastMM4Options.inc

+2

to trochę stary adres URL, nowy to github.com/pleriche/FastMM4 –

+0

może również przekierować go do obiektu Debug Strings Windows, ale nie sądzę, że jest to kwestia jego pytania. –

7

To jest błąd w najnowszych wersjach Delphi. Właśnie sprawdziłem to w najnowszym darmowym Delphi 10.1 Starter i zachowuje się zgodnie z opisem - ale ponieważ nie dostarcza źródeł RTL, nie mogę sprawdzić dokładnego powodu.

W Delphi XE2 zachowuje się zgodnie z oczekiwaniami: tworzy dialog modalny z zadaniami i czeka na reakcję, tak jak opisano to w Sertak.

W Delphi 10.1 wyciek jest rzeczywiście zgłaszany do okna konsoli, ale program nie jest zatrzymany, aby czekać na uwagę użytkownika. To jest złe rozwiązanie, zarówno z tego powodu, jak i dla możliwego wykorzystania programów konsolowych w skryptach (skrypty CMD lub PS nie "zrozumiałyby" tego komunikatu i mogłyby go zmylić z legalnym wyjściem i niepowodzeniem w wykonaniu dalszych programów etapów. Myślę, że musisz otworzyć raport błędu typu regresji w Delphi 10.0 - ale nie sądzę, że naprawiłby go do wydania 10.2.

Również zmieniłem twoją aplikację z rozwidlonego menedżera pamięci na oryginalny, a następnie błędne zachowanie zostało przywrócone: program wyświetlił okno komunikatu i czekał aż go zwolnię przed wyjściem do IDE.

Obecnie sugeruję używanie wspomnianego oryginalnego menedżera pamięci, a nie jego widelca Delphi.

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    FastMM4, 
    System.Classes, 
    System.SysUtils; 
... 

Oryginalny menedżer pamięci rezyduje w http://github.com/pleriche/FastMM4 Można używać klienta Git w Delphi lub samodzielnym jeden utrzymać się na bieżąco, można też pobrać kod raz i zatrzymać aktualizację, zależy od ciebie.

Odpowiednie cytaty z jego kod to:

{$ifdef LogErrorsToFile} 
    {Set the message footer} 
     LMsgPtr := AppendStringToBuffer(LeakMessageFooter, LMsgPtr, Length(LeakMessageFooter)); 
     {Append the message to the memory errors file} 
     AppendEventLog(@LLeakMessage[0], UIntPtr(LMsgPtr) - UIntPtr(@LLeakMessage[1])); 
    {$else} 
     {Set the message footer} 
     AppendStringToBuffer(LeakMessageFooter, LMsgPtr, Length(LeakMessageFooter)); 
    {$endif} 
    {$ifdef UseOutputDebugString} 
     OutputDebugStringA(LLeakMessage); 
    {$endif} 
    {$ifndef NoMessageBoxes} 
     {Show the message} 
     AppendStringToModuleName(LeakMessageTitle, LMessageTitleBuffer); 
     ShowMessageBox(LLeakMessage, LMessageTitleBuffer); 
    {$endif} 
    end; 
    end; 
{$endif} 
end; 

i

{Shows a message box if the program is not showing one already.} 
procedure ShowMessageBox(AText, ACaption: PAnsiChar); 
begin 
    if (not ShowingMessageBox) and (not SuppressMessageBoxes) then 
    begin 
    ShowingMessageBox := True; 
    MessageBoxA(0, AText, ACaption, 
     MB_OK or MB_ICONERROR or MB_TASKMODAL or MB_DEFAULT_DESKTOP_ONLY); 
    ShowingMessageBox := False; 
    end; 
end; 

Kod ten zależy prowadzony na pulpicie systemu Windows, więc może Embarcadero próbował „naprawić” to, aby przejechać -Platforma. Jednak sposób, w jaki to zrobili złamał go na konsoli Windows ....

Należy również rozważyć użycie innych form logowania - do pliku i/lub do ciągów Debug systemu Windows. Nie byłyby tak przyciągające uwagi jak okno modalne, ale przynajmniej pomogłyby w zapisaniu informacji, gdybyś wiedział, gdzie jej szukać.

4
var 
    SaveExitProcessProc: procedure; 
    s: TStringList; 

procedure MyExitProcessProc; 
begin 
    ExitProcessProc := SaveExitProcessProc; 
    readln; 
end; 

begin 
    SaveExitProcessProc := ExitProcessProc; 
    ExitProcessProc := MyExitProcessProc; 
    ReportMemoryLeaksOnShutdown := True; 
    s := TStringList.Create; 
end. 
+1

Błędy prawdopodobnie są spowodowane próbuje zdobyć pamięć do readln po sfinalizowaniu menedżera. W oknach można zastąpić skrzynką pocztową. –

+0

Skrzynka @SertacAkyuz Win32 ma problem: nie można skopiować tekstu z niego do schowka. JEŚLI to rzeczywiście potrzebne - ponownie zainstalowałbym menedżera pośredniczącego, przekierowując wszystkie wywołania Delphi do Win32 LocalAlloc i znajomych –

+0

@Arioch - To jest miejsce odczytu, aby zatrzymać wykonywanie - nie ma niczego do skopiowania. Po drugie, mylisz się, naciśnij ctrl + c na standardowym oknie komunikatu, a podpis i tekst oraz tekst przycisków zostaną skopiowane do schowka. –