【问题标题】:How to release memory used by IHTMLDocument?如何释放 IHTMLDocument 使用的内存?
【发布时间】:2011-08-28 10:18:57
【问题描述】:

使用 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,如果我运行这么多次,这可能会导致内存泄漏。

非常感谢

【问题讨论】:

  • EmptyWorkingSet 实际上并没有释放任何内存。它只是将活动内存分页到磁盘。您的进程仍然拥有该内存;访问它会将其分页回 RAM。您如何衡量您的进程的内存消耗,以及是什么让您认为您有问题需要解决?
  • 顺序可能重要吗?尝试首先nil分配给HTMLDocument,然后然后释放WebBrowser。另一个(可能不相关)的事情是,WebBrowser.Document 可能在Navigate 之后立即没有有效的IHtmlDocument2(页面可能仍在加载)。您可能应该使用像 OnDocumentComplete 这样的事件。
  • 只是一个想法:甚至可以在释放之前尝试Navigate('about:blank')
  • 还有一个想法:我记得在进程外 COM 类中遇到过类似问题,CoFreeUnusedLibrariesEx 解决了它。
  • 谢谢,很高兴能帮上忙! :-)

标签: delphi winapi memory com twebbrowser


【解决方案1】:

当您释放对 COM 类的所有引用时,通常应该释放它们。通常这可以通过将 nil 分配给所有持有对其接口的引用的变量来完成。

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

【讨论】:

  • 这就是我尝试过的,但它没有帮助。也许我只需要一个更好的内存计。我唯一知道的是,当我调用 EmptyWorkingSet 时,内存会减少(通过 Rob 提到的分页到我的磁盘),但 300 MB 的部分消失了。
  • 我认为要么您没有发布所有引用,要么您发现了一个错误(在 IE 控件本身或 Delphi/COM 层中)。先检查自己的代码。
  • 我一直在寻找原因,但我没有找到任何明智的解决方案。我的脚本有很多使用谷歌街景的实例,内存增加到提到的 300 MB,即使我将 HTMLDocuments 指向零,我也无法取回它。我不能在这里给出那个脚本,但即使你尝试我粘贴的代码,每个实例都会丢失大约 300 kB。无论如何+1的答案:)
【解决方案2】:

我不了解 Delphi,但我使用过 C++ 中的 IHTMLDocument。我相信您需要调用 Release() 方法。我也知道它使用BSTR 作为字符串,因此这可能是另一个寻找未释放内存的地方。

【讨论】:

  • Delphi 在接口指针上自动调用Release。不要手动调用它。 (有点像来自 ATL 的 CComPtr。)同样,BSTR 在 Delphi 中由 WideString 类型表示,并且 RTL 自动管理它们的生命周期,就像任何其他字符串一样。
【解决方案3】:

你试过 Navigate('about:blank');在释放之前?这应该已经释放了一些内存。我还认为 WebBrower 的内部结构(与 Internet Explorer 的内部结构大致相同)将很多东西保存在内存中,只是为了将历史记录和缓存提供给任何其他 TWebBrowser(或 IWebBrowser2更具体)可能存在于可执行文件的这个会话中,甚至在(不久的)将来。

运气好的话(如果您使用的是 Navigate 或 Navigate2),如果您使用 flags like navNoHistory, navNoWriteToCache 或其他人调用,则可以更改此设置。

【讨论】:

  • +1;看起来也很有希望;我会检查一下。我最大的问题解决了 CoFreeUnusedLibrariesEx,但它确实不会释放所有内容。谢谢!
【解决方案4】:

这个问题困扰TWebbrowser 用户多年,至今没有解决办法;释放 TWebbrowser 使用的内存的唯一方法是关闭您的应用并再次打开它。

【讨论】:

    猜你喜欢
    • 2014-04-18
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    相关资源
    最近更新 更多