为什么在执行应用程序的第一行代码之前调用 TObject.Free?

发布于 2024-10-23 15:01:37 字数 718 浏览 1 评论 0原文

我们正在尝试找出我们的软件中是否存在内存泄漏。因此,我一直在使用各种工具和程序来帮助我找到可能的内存泄漏。我使用的软件之一是 AQTime。由于它是与 Delphi XE 一起提供的,因此它只是一个演示。所以,我并没有真正能够从中获得任何有用的信息。然后,我决定使用免费软件MemProof。到目前为止,它向我展示了我们软件的许多需要注意的问题。其中之一是错误。

当我通过 MemProof 启动程序时,它会列出 2 个错误,这些错误试图从单元文件 system.pas 中销毁不存在的对象。因此,当我实际在 TObject.Free 过程中放置​​一个断点时,它甚至在我的程序完全启动之前就中断了。通过查看system.pas中的Free过程,我发现TIconimage正在尝试破坏或释放自身。换句话说,在实际启动之前,不会从我的程序中调用自由过程。

下面是实际的 Free 程序:

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

观察之后,我删除了断点,让程序一路运行。我的程序主窗口弹出,可供用户输入。然而,我还发现,如果我的程序的 WINDOW 的任何部分显示在屏幕上,TObject.Free 过程就会被不停地调用。我根本不明白这一点。这是为什么?谁能解释一下吗?当 TForm 显示在屏幕上时不断调用该过程时,TForm 与任何形状或形式的 TObject.Free 有何关系?

提前致谢。

We are trying to figure out if we have memory leaks in our software. So, I have been using various tools and programs to help me find possible memory leaks. One of the software I used was AQTime. As it came with Delphi XE, it was only a demo. So, I was not really able to get any useful information from it. Then, I decided to use free software, MemProof. So far, it has shown me many issues with our software that requires attention. One of which is an error.

As soon as I start my program through MemProof, it lists 2 errors, which is attempting to destroy non-existent object from the unit file, system.pas. So, when I actually put a break point within TObject.Free procedure, it breaks even before my program started all the way. Stepping through the procedure Free in system.pas, I found out that TIconimage is trying to destroy or free itself. In other word, free procedure is not invoked from within my program prior to actually starting up.

Here is the actual Free procedure:

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

After that observation, I removed the breakpoint and let the program run all the way. My programs main window popped up ready for user input. However, I also found out that TObject.Free procedure is invoked non-stop if any part of my program's WINDOW is displayed on the screen. I don't understand that at all. Why is that? Can anyone explain? How is TForm is related to TObject.Free in any shape or form as the procedure is constantly invoked when the TForm is displayed on the screen?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

如果没有 2024-10-30 15:01:37

关于为什么TObject.Free执行很多,每次销毁一个对象时,任何对象,都会调用该方法。所有类都派生自 TObject,它是共同的祖先,因此 Delphi 程序中的几乎所有操作都涉及大量对象创建/销毁对,因此将命中 TObject.Free

关于内存泄漏的检测,Delphi 内置了解决此问题所需的一切。 FastMM 内存管理器可以在“报告内存泄漏”模式下运行,它将为您提供泄漏的任何内存的大量诊断信息。

考虑以下简单的程序:

program Leaker;
begin
  ReportMemoryLeaksOnShutdown := True;
  TObject.Create;
end.

这会产生以下输出:

在此处输入图像描述

您只需设置 ReportMemoryLeaksOnShutdown 在应用程序中的某处设置为 True(.dpr 文件的开头是一个很好的地方)。

如果您希望在报告中收到更多信息,则可以下载 完整版 FastMM 并配置尽情享受吧。

然后你会得到这样的输出:

A memory block has been leaked. The size is: 84

This block was allocated by thread 0x1304, and the stack trace (return addresses) at the time was:
40455E [System][System.@GetMem]
405A2F [System][System.TObject.NewInstance]
40602E [System][System.@ClassCreate]
4474C2 [Classes][Classes.TStringList.Create]
C275A3 [Main.pas][Main][Main.TMainForm.CreateAuxiliaryForms][997]
C84C8A [OrcaFlex.dpr][OrcaFlex][OrcaFlex.OrcaFlex][351]
75E633CA [BaseThreadInitThunk]
77519ED2 [Unknown function at RtlInitializeExceptionChain]
77519EA5 [Unknown function at RtlInitializeExceptionChain]

The block is currently used for an object of class: TStringList

这真是太棒了。它告诉我泄漏的内存是在 Main.pas 第 997 行中分配的,而这正是我故意泄漏的地方!

Regarding why TObject.Free executes a lot, every single time an object is destroyed, any object, that method will be called. All classes derive from TObject, it's the common ancestor, so almost any action in a Delphi program involves large numbers of object create/destroy pairs and consequently will hit TObject.Free.

Regarding detection of memory leaks, you have all you need built in to Delphi to solve this. The FastMM memory manager can be run in "report memory leaks" mode and it will give you loads of diagnostics of any memory that you leak.

Consider the following trivial program:

program Leaker;
begin
  ReportMemoryLeaksOnShutdown := True;
  TObject.Create;
end.

This results in the following output:

enter image description here

You just need to set ReportMemoryLeaksOnShutdown to True somewhere in your app (the start of the .dpr file is as good a place as any).

If you wish to receive more information in the report then you can download the full version of FastMM and configure it to your heart's content.

Then you get output like this:

A memory block has been leaked. The size is: 84

This block was allocated by thread 0x1304, and the stack trace (return addresses) at the time was:
40455E [System][System.@GetMem]
405A2F [System][System.TObject.NewInstance]
40602E [System][System.@ClassCreate]
4474C2 [Classes][Classes.TStringList.Create]
C275A3 [Main.pas][Main][Main.TMainForm.CreateAuxiliaryForms][997]
C84C8A [OrcaFlex.dpr][OrcaFlex][OrcaFlex.OrcaFlex][351]
75E633CA [BaseThreadInitThunk]
77519ED2 [Unknown function at RtlInitializeExceptionChain]
77519EA5 [Unknown function at RtlInitializeExceptionChain]

The block is currently used for an object of class: TStringList

It's truly wonderful. It tells me that the leaking memory was allocated in Main.pas line 997, and that's precisely where I put my intentional leak!

那支青花 2024-10-30 15:01:37

如您所知,TApplication 有一个 Icon 属性,您可以在项目选项的应用程序设置中分配该属性。此属性通过 TApplication 的 FIcon 字段反映,该字段是在 Application 对象的构造函数中创建的。 TIcon 有一个 TIconImage 字段,表示在其构造函数中创建的实际图像。当应用程序对象加载并分配项目资源文件中的图标时,必须释放此初始“TIconImage”以防止泄漏。所有这些甚至在项目源代码中调用 Application.Initialize 之前就发生了,因为 Application 对象是从“controls.pas”的初始化部分构造的。

应用程序启动或运行时会发生很多事情。启动时,流机制创建对象(资源流、读取器、类查找器、组件列表......),然后释放它们。即使是空白的 VCL 窗体(上面没有控件)在运行时也会在每次激活时创建一个列表以查找要放置焦点的控件,然后释放该列表。对于复杂的 GUI 应用程序,即使将鼠标悬停在某物上,也可以创建和释放各种图形对象。或者,即使您将鼠标按在某物上,对齐/排列代码也可以创建/释放对象。

要调试泄漏,您可以学习 David 的回答概述的课程,或者使用第三方产品专注于其所说的泄露内容,而不是创建/释放的每个对象。 :)

As you know, TApplication has an Icon property which you can f.i. assign in the application settings in project options. This property is reflected with an FIcon field of TApplication which is created in the constructor of the Application object. TIcon has a TIconImage field representing the actual image which gets created in its constructor. When the Application object loads and assigns the icon from the project resource file, this initial 'TIconImage' has to be freed in order to prevent a leak. All this happens even before Application.Initialize is called in the project source, because the Application object is constructed from the initialization section of 'controls.pas'.

Lots of things are happening when an application is launching or running. When launching, the streaming mechanism creates objects (resource streams, readers, class finders, component lists ..) and then frees them. Even a blank VCL form (with no controls on it) when running, creates a list each time it gets activated to find a control to put the focus on, and then frees this list. With complex GUI applications, a variety of graphics objects can be created and freed even if you hover the mouse on something. Or the alignment/arrangement code can create/free objects even if you press your mouse on to something.

To debug leaks you can take the course outlined by David's answer, or when using a 3rd party product concentrate on what it says leaked, not on every object which gets created/freed. :)

无名指的心愿 2024-10-30 15:01:37

每当 Delphi 中类的任何实例被Free'd 时,TObject.Free 就会被调用。

这包括一系列简单地作为 Delphi 程序正常执行的一部分而创建和销毁的对象,包括响应由 TForm 对象自动处理的事件,以及响应由系统只是维护窗口对象本身存在于Windows自己的窗口管理器中。

例如,考虑从 TCustomForm WndProc 中截取的代码片段:

      WM_MEASUREITEM:
      begin
         :
                Canvas := TControlCanvas.Create;
                with Canvas do
                try
                  :
                finally
                  Canvas.Free;
                end;
        :
      end;

这里的关键是响应 WM_MEASUREITEM 消息,自定义表单(因此是标准的 WM_MEASUREITEM 消息) >TForm 派生类,因为它最终派生自 TCustomForm)创建一个临时 TControlCanvas,然后它释放已经完成了。

这可能不一定是您在特定表单的情况下看到的 TObject.Free 调用的来源,它只是一个示例,但显示了 TForm 如何仅仅存在可能会导致其他对象的存在和销毁,以响应系统自动生成的消息。

TObject.Free will be called whenever ANY instance of a class in Delphi is Free'd.

This includes a whole host of objects that are created and destroyed simply as part of the normal execution of a Delphi program, including in response to events processed automatically by a TForm object in response to the messages generated by the system simply to maintain the window object itself in existence in the Windows own Window Manager.

For example, consider this snipped fragment of code from the TCustomForm WndProc:

      WM_MEASUREITEM:
      begin
         :
                Canvas := TControlCanvas.Create;
                with Canvas do
                try
                  :
                finally
                  Canvas.Free;
                end;
        :
      end;

The key here being that in response to a WM_MEASUREITEM message, a custom form (and therefore a standard TForm derived class, since this ultimately derives from TCustomForm) creates a temporary TControlCanvas, which it then Free's when it is finished with it.

This may not necessarily be the source of the TObject.Free calls that you are seeing in your particular form's case, it is just an example, but shows how a TForm merely existing can result in other objects being brought into existence and destroyed in response to automatic, system generated messages.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文