如何释放IHTMLDocument使用的内存?

4

在使用IHTMLDocument(IHTMLDocument2)后,有没有一种释放内存的方法?

目前我正在使用EmptyWorkingSet函数,但我觉得这不是一个好方法。

EmptyWorkingSet(GetCurrentProcess);

即使释放TWebBrowser也没有帮助;问题似乎在于IHTMLDocument COM类没有被从内存中释放。是否有明确的方法来释放它;类似于Marshal.ReleaseComObject但适用于Delphi吗?
这可以通过比运行JavaScript少的内存丢失来重现,但仍然存在。如果您在表单顶部放置两个按钮并尝试以下代码...
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;

您会发现每次释放WebBrowser后,内存都会减少。当我运行我的JavaSrcipt时,它甚至超过了300 kB,大约为1 MB,这可能会导致内存泄漏,如果我多次运行它的话。谢谢!

1
EmptyWorkingSet 实际上并没有释放任何内存,它只是将活动内存分页到磁盘。你的进程仍然拥有那些内存;访问它会将其重新分页回 RAM。你是如何测量进程的内存消耗的?你认为自己需要解决什么问题呢? - Rob Kennedy
1
也许顺序很重要?尝试首先HTMLDocument赋值为nil,然后再释放WebBrowser。另一件(可能无关的)事情是,在Navigate之后,WebBrowser.Document可能还没有保存有效的IHtmlDocument2(页面可能仍在加载中)。您应该使用像OnDocumentComplete这样的事件。 - Ondrej Kelle
1
只是一个想法:在释放之前,甚至可以尝试使用 Navigate('about:blank') - Ondrej Kelle
1
还有一个想法:我记得我曾经遇到过一个类似的问题,是关于一个 out-of-process COM 类的,而 CoFreeUnusedLibrariesEx 解决了它。 - Ondrej Kelle
就是这个了,这就是我一直在寻找的!非常感谢!调用 CoFreeUnusedLibrariesEx(0, 0); 可以在使用 WebBrowser 后立即释放大内存块。 - user532231
显示剩余2条评论
4个回答

3

当您释放对COM类的所有引用时,通常应将其释放。通常可以通过将nil分配给保存其接口引用的所有变量来完成此操作。

要立即释放COM DLL使用的内存,可以使用CoFreeUnusedLibrariesEx


这就是我尝试过的,但没有帮助。也许我只需要一个更好的内存计量器。唯一我知道的是,当我调用EmptyWorkingSet时,内存会减少(通过像Rob提到的分页到我的磁盘),但那300 MB的部分消失了。 - user532231
2
我认为要么你没有释放所有的引用,要么你发现了一个错误(在IE控件本身或Delphi/COM层)。首先检查你自己的代码。 - Ondrej Kelle
1
我已经寻找原因很长时间了,但是我没有找到任何合理的解决方案。我的脚本使用了许多Google街景实例,内存增加到了提到的300 MB,即使我将HTMLDocuments指向nil,也无法恢复。我不能在这里提供那个脚本,但是即使您尝试我粘贴的代码,每个实例也会失去约300 kB。无论如何,感谢回答 :) - user532231

0

这个问题困扰着TWebbrowser用户已经很长时间了,目前还没有解决办法;释放TWebbrowser使用的内存的唯一方法是关闭您的应用程序,然后再次打开它。


0
我不懂 Delphi,但我曾在 C++ 中使用过 IHTMLDocument。我相信你需要调用 Release() 方法。我还知道它使用 BSTR 作为字符串,所以这可能是另一个需要查找未释放内存的地方。

4
Delphi会自动调用接口指针的Release方法,不需要手动调用(这有点类似ATL中的CComPtr)。同样,BSTR在Delphi中使用WideString类型表示,并且RTL会自动管理它们的生命周期,就像其他字符串一样。 - Rob Kennedy

0

在释放之前,您尝试过Navigate('about:blank')吗?这应该已经释放了一些内存。我还认为WebBrower的内部(与Internet Explorer大致相同)会将许多东西保存在内存中,以便为此执行文件中可能存在的任何其他TWebBrowser(或更具体地说是IWebBrowser2)提供历史记录和缓存,即使在(接近的)未来也是如此。

运气好的话(如果您正在使用Navigate或Navigate2),您可以通过调用{{link1:类似navNoHistory、navNoWriteToCache的标志}}和其他一些标志来改变这种情况。


+1;看起来很有前途;我会去试试。我的最大问题得到了解决CoFreeUnusedLibrariesEx,但它确实没有释放所有东西。谢谢! - user532231

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接