Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

delphi

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 this 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.

like image 761
David Heffernan Avatar asked Feb 15 '11 20:02

David Heffernan


2 Answers

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.

like image 70
Rob Kennedy Avatar answered Nov 07 '22 19:11

Rob Kennedy


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.
    
like image 24
Nitrowares Development Avatar answered Nov 07 '22 17:11

Nitrowares Development