开发者

Why does Themes.pas leak the TThemeServices singleton when linked into a DLL

开发者 https://www.devze.com 2023-02-11 04:27 出处:网络
Update:The changes to introduce VCL styles in XE2 have removed the memory leak. So I guess it was unintentional after all.

Update: The changes to introduce VCL styles in XE2 have removed the memory leak. So I guess it was unintentional after all.


I came across a VCL memory leak today, in Themes.pas. It only occurs for DLLs. The unit finalization code is as so:

finalization
  if not IsLibrary then
    InternalServices.Free;

InternalServices is a singleton that is created on demand when you call the ThemeServices function. Many DLLs do not have UI and so do not ever create this singleton. However, I happen to have a COM add-in to Excel which does result in this leak manifesting.

The leak doesn't particularly bother me because thi开发者_如何转开发s DLL is never repeatedly loaded and unloaded from the same process. And I know how I could fix the leak using the ThemeServicesClass global variable.

My question though, is to ask if anyone can explain why this code is the way it is. It seems quite deliberately coded this way. For the life of me I cannot come up with an explanation for this intentional leak.


One explanation is that the unit finalization section is executed while the OS loader lock is active. During that time, there are significant restrictions on what a DLL is allowed to do without risking deadlock.


We run into this same problem as well. Here is what we are currently doing to prevent the leak in our projects:

  1. In the dll .dpr file add Themes to the uses section.

  2. Add the following to clean up the leak on shutdown:

    procedure DLLEntryProc(EntryCode: integer);
    begin
      case EntryCode of
      DLL_PROCESS_DETACH:
      begin
        ThemeServices.Free;
      end;
      DLL_PROCESS_ATTACH:
      begin
      end;
      DLL_THREAD_ATTACH:
      begin
      end;
      DLL_THREAD_DETACH:
      begin
      end;
      end;
    end;
    
    begin
      {$IFDEF DEBUG}
      ReportMemoryLeaksOnShutdown  := True;
      {$ENDIF}
      DllProc := @DLLEntryProc;
    end.
    


On the same idea that there must be a good reason to leave it leaking (indy leaks a couple of things on purpose as well, or at least it used to) I prefer to ignore it, like so:

{$I FastMM4Options.inc}
...
{$IFDEF EnableMemoryLeakReporting}
  if IsLibrary then// ThemeServices is leaked when created in a DLL.
    RegisterExpectedMemoryLeak(ThemeServices);
{$ENDIF}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号