4

My application uses a TWebBrowser that loads a webpage. The problem is, after closing the form containing the TWebBrowser, the memory used is not freed. If I open and close the form, the memory just keeps on increasing.

Saw some post regarding calling SetProcessWorkingSetSize() or CoFreeUnusedLibrariesEx() to solve this issue, but I'm not sure if any of these are the correct solution.

Any idea how to free the memory used by TWebBrowser?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Wilbert Chua
  • 101
  • 1
  • 5
  • 6
    I expect that you are probably mis-interpreting whatever it is you are using to gather these statistics. Heap allocators are very complex and it's perfectly common for them to hold on to memory until they need to release it. If the system has plenty of memory available, why spend time returning it to the OS when you can hang on to it for free. – David Heffernan Apr 19 '12 at 09:04
  • 1
    How are you closing (and opening) the form, and is it freed by anything? Source please. – mj2008 Apr 19 '12 at 09:57
  • Do you still have the memory problem if you open and close the form without loading the web page? – Sam M Apr 19 '12 at 16:45
  • 3
    An example of such leaking application you may find [`here`](http://stackoverflow.com/a/9533101/960757). Even if the form with `TWebBrowser` as a component is released the threads remains running and new ones are created with each new instance (so the memory consumption increases). I haven't found a solution, I was trying many ways, including `CoFreeUnusedLibrariesEx`, navigating to `about:blank`, nothing helped. And it's a serious problem because creating several form instances costs many system resources. My suggestion is to hide the form, not release, because it seems it has no effect here. – TLama Apr 19 '12 at 21:24
  • After years, no solution so far : / – delphirules Apr 28 '16 at 22:18
  • I spent a lot of time and effort on this, and concluded that some websites are poorly coded and nothing will free the memory, even freeing the TWebBrowser component. My solution was simply to close the application and restart it once the memory limit was approached. The close/restart was automated. – Kevin Davidson Jul 21 '21 at 14:06

6 Answers6

5

QC#106829 describes one possible cause of memory leaks with TWebBrowser. Accessing Document (and any other properties that are implemented via TOleControl.GetIDispatchProp or TOleControl.GetIUnknownProp) causes leaks because it calls AddRef without ever calling Release. As a workaround, you can manually call Release, or you can patch the VCL (see here), or you can avoid the problematic properties (for example, by using browser.DefaultInterface.Document instead of browser.Document).

Josh Kelley
  • 56,064
  • 19
  • 146
  • 246
1

Using TWebBrowser does a lot of work behind the scenes, much of the same work a full instance of Internet Explorer would do. It is hidden from you, but still it's there and chances are it's unaccessible for us to force removing from memory. Check the memory usage before and between page loads, and test what happens when you call Navigate('about:blank');. Also check whether your destructor gets called properly, and consider calling Navigate('about:blank'); from OnClose or OnCloseQuery. I found this does help the memory-situation a little bit.

Stijn Sanders
  • 35,982
  • 11
  • 45
  • 67
0

The best solution is STOP using TWebbrowser.

CEF4Delphi is a free library that uses Chrome instead of Internet Explorer. Always up to date and very efficient :

https://github.com/salvadordf/CEF4Delphi

delphirules
  • 6,443
  • 17
  • 59
  • 108
-1
Uses Winapi.PsAPI;
 ...
{$IFDEF WIN32}
procedure TForm1.MemoryFree;
var
  HandleCaptureProcessus: THandle;
  UnProcessus: TProcessEntry32;
  PIDProcessus: THandle;
  HandleProcessus: THandle;
  NameOfProcess: string;
begin
  PIDProcessus := 4294967295;
  NameOfProcess := ExtractFileName(Application.ExeName);

  HandleCaptureProcessus := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  UnProcessus.dwSize := SizeOf(TProcessEntry32);

  Process32First(HandleCaptureProcessus, UnProcessus);
  repeat
    if UnProcessus.szExeFile = NameOfProcess then
    begin
      PIDProcessus := UnProcessus.th32ProcessID;
      Break;
    end;
  until not Process32Next(HandleCaptureProcessus, UnProcessus);

  if PIDProcessus = 4294967295 then
  begin
    CloseHandle(HandleCaptureProcessus);
    exit;
  end;

  HandleProcessus := OpenProcess(PROCESS_ALL_ACCESS, False, PIDProcessus);

  EmptyWorkingSet(HandleProcessus);

  CloseHandle(HandleProcessus);
end;
{$ELSE}
procedure TForm1.MemoryFree;
begin
  //**
end;
{$ENDIF}

To clear the memory, I use this function, found somewhere on the forums. It clears the "Working Set" much better than the SetProcessWorkingSetSize () method, but it is more difficult to call and it is registered in the Winapi.PsAPI unit. But, I noticed that both of these functions clean the "Working Set". And if you look at the "Allocated memory" column in the Task Manager, you can see that this parameter is not cleared. The "working set" of my application after cleaning can be reduced to 10 MB, but the all allocated memory will remain equal to 1.5 GB. And, in my opinion, this is what causes the error "Out of memory". And this error still appears if you look at heavy websites for a long time.

-2

To free up the memory, just initialize the new document:

(WebBrowser.Document as IPersistStreamInit).InitNew;
HemChe
  • 2,249
  • 1
  • 21
  • 33
-2
procedure TForm1.FreeMemory;
begin
    if Win32Platform = VER_PLATFORM_WIN32_NT then
    SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
end;

and call it from time to time

FreeMemory;
  • This solution does not work ; it simply 'compacts' the memory used but after a new navigate all huge memory used before are alocated again. – delphirules Feb 05 '15 at 21:13