使用控制台应用程序报告关闭时的内存泄漏
Reporting memory leaks on shutdown with a console application
我创建了一个控制台应用程序并设置 ReportMemoryLeaksOnShutdown := True。
我创建了一个 TStringList 但没有释放它。
当程序完成执行时,我看到内存泄漏一秒钟,然后控制台关闭。
我试过添加 ReadLn;到最后,但当我这样做时它只显示一个空白控制台 window,这是有道理的。
我需要找到一种在内存泄漏报告之后但在程序完全关闭之前暂停执行的方法。
我正在使用 Delphi 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.
最简单的方法是 运行 以前打开的命令中的应用程序 window。
如果您在 IDE 中 运行 时坚持要查看内存泄漏报告,请执行以下操作:
- 在 GetMem.inc 中找到 ShowMessage 过程(Delphi 10 Seattle 中的第 4856 行)
- 在该过程的
end;
处放置一个断点。
或者,正如 Sertac Akyuz 评论的那样,在 system
单元的 end.
上放置一个断点。
您还可以将内存泄漏报告重定向到一个文件。从
下载完整版 FastMM
https://sourceforge.net/projects/fastmm/
或更好,感谢 Arioch 'The,来自这里:
https://github.com/pleriche/FastMM4
并在FastMM4Options.inc
中设置需要的选项
这是最近 Delphi 版本中的错误。我刚刚在最近的免费 Delphi 10.1 Starter 中检查了它,它的行为与您描述的一样 - 但由于它不提供 RTL 源,我无法检查确切原因。
在 Delphi XE2 中,它的行为符合预期:创建任务模式对话框并等待您做出反应,就像 Sertak 所描述的那样。
在Delphi 10.1 中确实向控制台报告了泄漏window,但程序并未停止以等待用户注意。这是一个糟糕的解决方案,出于这个原因以及可能在脚本中使用控制台程序(CMD 或 PS 脚本不会 "understand" 此消息并且可能将其与合法输出混淆并无法执行进一步的阶段程序。
我认为您必须在 Delphi 10.0 上打开回归类型的错误报告 - 但我认为他们会在 10.2 发布之前修复它。
我还将您的应用程序从 Delphi-forked 内存管理器切换到原始应用程序,然后错误行为被恢复:程序显示消息框并等到我关闭它才退出 IDE.
目前我建议您使用提到的原始内存管理器而不是 Delphi 它的分支。
program Project1;
{$APPTYPE CONSOLE}
uses
FastMM4,
System.Classes,
System.SysUtils;
...
原来的内存管理器驻留在http://github.com/pleriche/FastMM4
您可以在 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;
和
{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 可能会尝试 "fix" 使其跨平台。然而,他们这样做的方式在 Windows 控制台上破坏了它....
还可以考虑使用添加其他形式的日志记录 - 将文件 and/or 添加到 Windows 调试字符串中。它们不会像模式 window 那样引人注目,但至少可以帮助您保存信息,如果您知道在哪里可以找到它的话。
var
SaveExitProcessProc: procedure;
s: TStringList;
procedure MyExitProcessProc;
begin
ExitProcessProc := SaveExitProcessProc;
readln;
end;
begin
SaveExitProcessProc := ExitProcessProc;
ExitProcessProc := MyExitProcessProc;
ReportMemoryLeaksOnShutdown := True;
s := TStringList.Create;
end.
这当然是 hack,不要在生产中使用 :)
ReportMemoryLeaksOnShutdown:= True;
IsConsole:= False;
TStringList.Create;
但是,它会导致泄漏消息(和一些其他消息)显示在消息框中(可以通过按 Ctrl+C 复制所有文本)。
(使用 Delphi 10.2 测试,请报告我们不喜欢的任何副作用)
我创建了一个控制台应用程序并设置 ReportMemoryLeaksOnShutdown := True。
我创建了一个 TStringList 但没有释放它。
当程序完成执行时,我看到内存泄漏一秒钟,然后控制台关闭。
我试过添加 ReadLn;到最后,但当我这样做时它只显示一个空白控制台 window,这是有道理的。
我需要找到一种在内存泄漏报告之后但在程序完全关闭之前暂停执行的方法。
我正在使用 Delphi 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.
最简单的方法是 运行 以前打开的命令中的应用程序 window。
如果您在 IDE 中 运行 时坚持要查看内存泄漏报告,请执行以下操作:
- 在 GetMem.inc 中找到 ShowMessage 过程(Delphi 10 Seattle 中的第 4856 行)
- 在该过程的
end;
处放置一个断点。
或者,正如 Sertac Akyuz 评论的那样,在 system
单元的 end.
上放置一个断点。
您还可以将内存泄漏报告重定向到一个文件。从
下载完整版 FastMMhttps://sourceforge.net/projects/fastmm/
或更好,感谢 Arioch 'The,来自这里:
https://github.com/pleriche/FastMM4
并在FastMM4Options.inc
这是最近 Delphi 版本中的错误。我刚刚在最近的免费 Delphi 10.1 Starter 中检查了它,它的行为与您描述的一样 - 但由于它不提供 RTL 源,我无法检查确切原因。
在 Delphi XE2 中,它的行为符合预期:创建任务模式对话框并等待您做出反应,就像 Sertak 所描述的那样。
在Delphi 10.1 中确实向控制台报告了泄漏window,但程序并未停止以等待用户注意。这是一个糟糕的解决方案,出于这个原因以及可能在脚本中使用控制台程序(CMD 或 PS 脚本不会 "understand" 此消息并且可能将其与合法输出混淆并无法执行进一步的阶段程序。
我认为您必须在 Delphi 10.0 上打开回归类型的错误报告 - 但我认为他们会在 10.2 发布之前修复它。
我还将您的应用程序从 Delphi-forked 内存管理器切换到原始应用程序,然后错误行为被恢复:程序显示消息框并等到我关闭它才退出 IDE.
目前我建议您使用提到的原始内存管理器而不是 Delphi 它的分支。
program Project1;
{$APPTYPE CONSOLE}
uses
FastMM4,
System.Classes,
System.SysUtils;
...
原来的内存管理器驻留在http://github.com/pleriche/FastMM4 您可以在 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;
和
{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 可能会尝试 "fix" 使其跨平台。然而,他们这样做的方式在 Windows 控制台上破坏了它....
还可以考虑使用添加其他形式的日志记录 - 将文件 and/or 添加到 Windows 调试字符串中。它们不会像模式 window 那样引人注目,但至少可以帮助您保存信息,如果您知道在哪里可以找到它的话。
var
SaveExitProcessProc: procedure;
s: TStringList;
procedure MyExitProcessProc;
begin
ExitProcessProc := SaveExitProcessProc;
readln;
end;
begin
SaveExitProcessProc := ExitProcessProc;
ExitProcessProc := MyExitProcessProc;
ReportMemoryLeaksOnShutdown := True;
s := TStringList.Create;
end.
这当然是 hack,不要在生产中使用 :)
ReportMemoryLeaksOnShutdown:= True;
IsConsole:= False;
TStringList.Create;
但是,它会导致泄漏消息(和一些其他消息)显示在消息框中(可以通过按 Ctrl+C 复制所有文本)。
(使用 Delphi 10.2 测试,请报告我们不喜欢的任何副作用)