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

Delphi 使用控制台应用程序报告关机时的内存泄漏,delphi,memory-leaks,delphi-10-seattle,Delphi,Memory Leaks,Delphi 10 Seattle,我已经创建了一个控制台应用程序,并将ReportMemoryLeaksOnShutdown:=设置为True 我创建了一个TStringList,但没有释放它 当程序完成执行时,我看到内存泄漏了一小秒,但随后控制台关闭 我试着添加一个ReadLn;最后,当我这样做时,它只显示一个空白的控制台窗口,这是有意义的 我需要找到一种方法,在内存泄漏报告之后,但在程序完全关闭之前暂停执行 我用的是德尔福10西雅图 program Project1; {$APPTYPE CONSOLE} uses

我已经创建了一个控制台应用程序,并将ReportMemoryLeaksOnShutdown:=设置为True

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

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

我试着添加一个ReadLn;最后,当我这样做时,它只显示一个空白的控制台窗口,这是有意义的

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

我用的是德尔福10西雅图

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.

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

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

  • 在GetMem.inc中找到ShowMessage过程(Delphi 10中的第4856行)
  • 端放置断点
或者,正如Sertac Akyuz所评论的,在
系统的
末端设置一个断点

您还可以将内存泄漏报告重定向到文件。从下载FastMM的完整版本

或者更好,多亏了Arioch'The,从这里:


并在
FastMM4Options.inc

中设置所需的选项,这在最近的Delphi版本中是一个bug。我刚刚在最近的免费Delphi10.1初学者中检查了它,它的行为与您描述的一样-但是由于它没有提供RTL源代码,我无法检查确切的原因

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

在Delphi10.1中,泄漏确实会报告到控制台窗口,但程序不会停止以等待用户注意。这是一个糟糕的解决方案,由于这一原因以及可能在脚本(CMD或PS)中使用控制台程序,脚本无法“理解”此消息,可能会将其与合法输出混淆,并导致后续程序的执行失败

我认为您必须在Delphi10.0上打开回归类型错误报告-但我认为他们在10.2版本之前不会修复它

我还将您的应用程序从Delphi forked memory manager切换到原来的内存管理器,然后错误行为被恢复:程序显示消息框并等待直到我将其关闭,然后退出IDE

目前,我建议您使用前面提到的原始内存管理器,而不是它的Delphi分支

program Project1;

{$APPTYPE CONSOLE}

uses
  FastMM4,
  System.Classes,
  System.SysUtils;
...
原始内存管理器位于 您可以在Delphi中使用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;

此代码取决于是否在桌面Windows上运行,因此可能Embarcadero试图“修复”它以使其跨平台运行。然而,他们这样做的方式在Windows控制台上破坏了它


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

< P>这当然是一个黑客,不要在生产中使用:

var
  SaveExitProcessProc: procedure;
  s: TStringList;

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

begin
  SaveExitProcessProc := ExitProcessProc;
  ExitProcessProc := MyExitProcessProc;
  ReportMemoryLeaksOnShutdown := True;
  s := TStringList.Create;
end.
但是,它会导致泄漏消息(以及一些其他消息)显示在消息框中(按Ctrl+C可以复制所有文本)


(使用Delphi 10.2测试,请报告我们不喜欢的任何副作用)

在以前打开的命令窗口中运行该程序,而不是在IDE中。您可以尝试我的
自动解决
单元,请参见此处:。只需将其添加到您的控制台程序中。在“system.end”上添加断点。FWIW我必须按“Ok”关闭XE2-system.ScanForMemoryLeaks调用MessageBoxA中的对话框,该对话框会阻止执行。@SertacAkyuz他们在稍后的Delphi中对其进行了“优化”:-/这是一个有点旧的URL,新的是github.com/pleriche/fastm4he。他也可以将其重定向到Windows调试字符串工具,但我不认为这是他的问题。错误可能是因为在管理器完成后试图获取readln的内存。windows上的可替换为messagebox。@SertacAkyuz Win32 messagebox有一个问题:无法将文本从中复制到剪贴板。如果确实需要,我会重新安装一个存根管理器,将所有Delphi调用路由到Win32 LocalAlloc和friends@Arioch-它代替了readln,停止执行-没什么可复制的。其次,你错了,在标准api消息框上按ctrl+c,标题、文本和按钮文本将被复制到剪贴板。@Arioch-我刚刚测试过,可以确认它在XP上工作。我相当肯定它在2K上也能工作,但我已经没有2K虚拟机了。@Arioch'事实上,情况正好相反。Windows是第一个具有消息框复制行为的系统(在Windows 2000 Beta中)。然后在RAID(在QC之前)中提出了一个建议,为VCL添加复制行为,因为测试人员厌倦了添加屏幕截图,然后键入文本以便能够搜索线程。这是对所问问题的完美解决方案!只需添加
IsConsole:=false和一个消息框将显示内存泄漏信息。
var
  SaveExitProcessProc: procedure;
  s: TStringList;

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

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