使用控制台应用程序报告关闭时的内存泄漏

时间:2016-09-19 18:24:18

标签: delphi memory-leaks delphi-10-seattle

我已经创建了一个控制台应用程序并设置了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.

4 个答案:

答案 0 :(得分:7)

这是最近Delphi版本中的一个错误。我刚刚在最近的免费Delphi 10.1 Starter中检查了它,它的行为和你描述的一样 - 但由于它没有提供RTL源,我无法检查确切的原因。

在Delphi XE2中,它的行为符合预期:创建任务模式对话框并等待您做出反应,就像Sertak所描述的那样。

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

我认为你必须在Delphi 10.0上打开回归型错误报告 - 但我认为他们不会在10.2发布之前修复它。

我还将你的应用程序从Delphi-forked内存管理器切换到原来的那个,然后错误的行为被还原了:程序显示了消息框,等到我退出之后再退出IDE。

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

program Project1;

{$APPTYPE CONSOLE}

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

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

其代码的相关引用是:

  {$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上运行,因此也许Embarcadero试图“修复”它以使其跨平台。但是他们这样做的方式在Windows控制台上打破了它....

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

答案 1 :(得分:6)

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

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

  • 在GetMem.inc中找到ShowMessage过程(Delphi 10 Seattle中的第4856行)
  • 在该程序的end;上放置一个断点。

或者,正如Sertac Akyuz评论的那样,在end.单位的system上设置一个断点。

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

下载完整版的FastMM

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

或更好,感谢Arioch' The,从这里:

https://github.com/pleriche/FastMM4

并在FastMM4Options.inc

中设置所需的选项

答案 2 :(得分:5)

var
  SaveExitProcessProc: procedure;
  s: TStringList;

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

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

答案 3 :(得分:1)

这肯定是一个hack,不要在生产中使用:)

<assemblyBinding>

但是,它导致泄漏消息(和其他一些消息)显示在消息框中(可以通过按Ctrl + C复制所有文本)。

(已在Delphi 10.2中进行了测试,请报告我们不希望出现的任何副作用)