2016-09-19 91 views
6

我创建了控制台应用程序并设置了ReportMemoryLeaksOnShutdown:= True。使用控制台应用程序关闭时报告内存泄漏

我创建了TStringList,但没有释放它。

当程序完成执行时,我看到内存泄漏一秒钟,但随后控制台关闭。

我试过添加一个ReadLn;到最后,但它只显示一个空白的控制台窗口,当我这样做,这是有道理的。

我需要找到一种方法,在内存泄漏报告之后,但在完成程序关闭之前暂停执行。

我正在使用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

在以前打开的命令窗口中运行程序,而不是在IDE中运行。 –

+1

你可以尝试***我的'AutoConsole'单元,请看这里:http://rvelthuis.blogspot.de/2016/07/new-velthuisautoconsole-unit.html。只需将其添加到您的控制台程序。 –

+0

在“system.end”上添加一个断点。 –

回答

6

最简单的方法就是在先前打开的命令窗口中运行应用程序。

如果你坚持看到内存泄漏报告在IDE中运行时,请执行以下操作:

  • 定位GetMem.inc的ShowMessage过程(线4856在Delphi西雅图10)
  • 放置一个该程序的end;断点。

或者,正如Sertac Akyuz评论说的,在system单位的end.上划了一个断点。

您也可以将内存泄漏报告重定向到一个文件。从

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

或更好,这要归功于亚略“下载完整版FastMM的,从这里开始:

https://github.com/pleriche/FastMM4

FastMM4Options.inc

+2

这是一个旧的URL,新的一个是github.com/pleriche/FastMM4 –

+0

他也可以将它重定向到Windows Debug Strings工具,但我不认为这是他的问题 –

7

被设置所需的选项最近的Delphi版本中的一个错误。我刚刚在最近免费的Delphi 10.1 Starter中检查过它,它的行为与你描述的一样 - 但由于它没有提供RTL源,所以我无法检查确切的原因。

在Delphi XE2中,其行为如预期:创建任务模式对话框并等待您作出反应,就像Sertak所述。

在Delphi 10.1中,泄漏确实被报告给控制台窗口,但程序没有停下来等待用户注意。这是一个糟糕的解决方案,因为这个原因以及在脚本编程中可能使用控制台程序(CMD或PS脚本不会“理解”该消息,并且可能会将其与合法输出混淆,并且不能执行进一步的舞台程序。

我认为你必须通过Delphi 10.0打开回归类型的错误报告 - 但我认为他们不会在10.2版本之前解决它。

我也将你的应用程序从Delphi分叉的内存管理器切换到原始的,然后错误的行为被恢复:程序显示消息框并等到我退出IDE之前将其解除。

目前我建议你使用提到的原始内存管理器而不是Delphi的fork。

program Project1; 

{$APPTYPE CONSOLE} 

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

原来的内存管理器驻留在http://github.com/pleriche/FastMM4 还可以使用Git客户端在你的Delphi或独立一个让自己保持更新,也可以一次下载代码并停止更新,给你。

其代码的相关报价是:

{$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; 

{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; 

该代码取决于是否在桌面上Windows上运行,所以也许E​​mbarcadero公司试图“修复”它,使其跨越-平台。然而,他们的方式,它打破了Windows控制台....

还可以考虑使用添加其他形式的日志记录 - 到文件和/或到Windows调试字符串。他们不会像模态窗口那么引人注目,但至少可以帮助你保存信息,如果你知道在哪里寻找它的话。

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

错误可能是由于试图在经理完成后为readln获取内存。在Windows上可以用消息框替换。 –

+0

@SertacAkyuz Win32 messagebox有一个问题:你不能从它复制文本到剪贴板。如果实际需要 - 我会重新安装存根管理器,将所有Delphi调用路由到Win32 LocalAlloc和朋友 –

+0

@Arioch - 它代替readIn,停止执行 - 没有任何可复制的东西。其次,你错了,在标准api消息框上按ctrl + c,标题,文本和按钮的文本将被复制到剪贴板。 –