4

is there a way to release memory after using IHTMLDocument (IHTMLDocument2) ?

Currently I'm using EmptyWorkingSet function but I feel that it's not a good way to do it

EmptyWorkingSet(GetCurrentProcess);

Even freeing the TWebBrowser doesn't help; the problem seems to be in IHTMLDocument COM class which is not released from the memory. Is there a clear way to release it; something like Marshal.ReleaseComObject but available for Delphi ?

It's reproducable with less memory lose than with running JavaScript, but still. If you put two buttons on the top of the form and try the following code ...

uses MSHTML, SHDocVw;

type
  TForm1 = class(TForm)
  private
    WebBrowser: TWebBrowser;
    HTMLDocument: IHTMLDocument2;
  end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  WebBrowser := TWebBrowser.Create(nil);
  TWinControl(WebBrowser).Parent := Self;
  WebBrowser.SetBounds(8, 39, ClientWidth-16, ClientHeight-47);
  WebBrowser.Navigate('http://maps.google.com/');
  HTMLDocument := WebBrowser.Document as IHTMLDocument2;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  WebBrowser.Free;
  HTMLDocument := nil;
end;

You will see the memory lose after each WebBrowser freeing. When I run my JavaSrcipt it's much even more than 300 kB, it's about 1 MB and this may cause a memory leak in case I'm running this many times.

Thanks a lot

  • 1
    `EmptyWorkingSet` doesn't actually release any memory. It just pages active memory to disk. Your process still owns that memory; accessing it will page it back into RAM. How are you measuring your process's memory consumption, and what makes you think you have a problem to fix at all? – Rob Kennedy May 18 '11 at 22:06
  • I'm using only the standard Windows TaskManager. I'm working with my GoogleMaps script and when I get into StreetView, working set (as it's probably called in english Windows version) increases up to 300 MB and it looks it remains there. –  May 18 '11 at 22:16
  • 1
    Is perhaps the order important? Try *first* assigning `nil` to `HTMLDocument` and *then* freeing `WebBrowser`. Another (possibly unrelated) thing is, `WebBrowser.Document` may not hold a valid `IHtmlDocument2` yet immediately after `Navigate` (the page may still be loading). You should probably use an event like `OnDocumentComplete`. – Ondrej Kelle May 19 '11 at 09:45
  • 1
    Just an idea: maybe even try `Navigate('about:blank')` before freeing. – Ondrej Kelle May 19 '11 at 09:53
  • @TOndrej - that's exactly what I've done; for waiting to document load I've tried both - `OnDocumentComplete` event and waiting for `TWebBrowser.ReadyState = READYSTATE_COMPLETE` in a loop, so there should be a valid document. And `Navigate('about:blank')` doesn't help, I though it may release the document somehow too, but there must be such kind of a cache for navigating back to the previous page. But thanks for the ideas. –  May 19 '11 at 10:19
  • 1
    One more idea: I remember having a similar issue with an out-of-process COM class and [CoFreeUnusedLibrariesEx](http://msdn.microsoft.com/en-us/library/ms678413%28v=vs.85%29.aspx) solved it. – Ondrej Kelle May 19 '11 at 10:31
  • That's it; that's what I was looking for ! Thanks a lot ! Calling `CoFreeUnusedLibrariesEx(0, 0);` releases the large memory block immediately after using WebBrowser. –  May 19 '11 at 10:58

4 Answers4

3

The COM classes should normally be freed when you release all references to them. Usually this can be done by assigning nil to all variables holding references to their interfaces.

For immediate release of memory used by COM DLLs you can use CoFreeUnusedLibrariesEx.

Ondrej Kelle
  • 36,941
  • 2
  • 65
  • 128
  • That's what I've tried, but it doesn't help. Maybe I just need a better memory meter. The only thing I know is that when I call `EmptyWorkingSet` the memory decreases (by paging to my disk as Rob mentioned) but that 300 MB part disappears. –  May 18 '11 at 22:23
  • 2
    I think either you don't release all references or you've found a bug (in the IE control itself or the Delphi/COM layer). Check your own code first. – Ondrej Kelle May 18 '11 at 22:30
  • 1
    I've been searching for the reason for a long time but I haven't found any sensible solution. With my script with many instances using Google's StreetView the memory increases up to the mentioned 300 MB and I can't get it back even if I point the HTMLDocuments to nil. I can't give here that script but even if you try the code I've pasted you'll lose about 300 kB with each instance. +1 for the answer anyway :) –  May 18 '11 at 23:49
0

This problem is plaguing TWebbrowser users for ages and there is no solution so far ; the only way to release the memory used by TWebbrowser is to close your app and open it again.

delphirules
  • 6,443
  • 17
  • 59
  • 108
0

I don't know Delphi but I've worked with IHTMLDocument in C++. I believe you need to call the Release() method. I also know it uses BSTR for strings so that might be another place to look for memory not being released.

daalbert
  • 1,465
  • 9
  • 7
  • 4
    Delphi calls `Release` on interface pointers automatically. Do not call it manually. (It's a little like `CComPtr` from ATL.) Likewise, BSTR is represented in Delphi by the `WideString` type, and the RTL manages their lifetimes automatically, just like any other strings. – Rob Kennedy May 18 '11 at 22:19
0

Have you tried Navigate('about:blank'); before freeing? This should already free some memory. I also think the internals from WebBrower (which are roughly the same internals as Internet Explorer), keep a lot of things in memory, just to serve the history and cache to any other TWebBrowser (or IWebBrowser2 to be more specific) that may exist in this session of the executable, even in the (near) future.

With a bit of luck (and if you are using Navigate or Navigate2), you could change this if you call with flags like navNoHistory, navNoWriteToCache and perhaps others.

Stijn Sanders
  • 35,982
  • 11
  • 45
  • 67
  • +1; also looks promisingly; I'll check this out. My biggest problem solved CoFreeUnusedLibrariesEx, but it's true that it doesn't release everything. Thanks ! –  May 19 '11 at 18:05