【问题标题】:Delphi TWebBrowser Memory LeakDelphi TWebBrowser 内存泄漏
【发布时间】:2012-04-19 09:00:02
【问题描述】:

我的应用程序使用加载网页的 TWebBrowser。问题是,在关闭包含 TWebBrowser 的表单后,使用的内存没有被释放。如果我打开和关闭表单,内存只会不断增加。

看到一些关于调用 SetProcessWorkingSetSize() 或 CoFreeUnusedLibrariesEx() 来解决这个问题的帖子,但我不确定这些是否是正确的解决方案。

知道如何释放 TWebBrowser 使用的内存吗?

【问题讨论】:

  • 我预计您可能会误解您用来收集这些统计信息的任何内容。堆分配器非常复杂,它们在需要释放内存之前一直保留内存是非常常见的。如果系统有足够的可用内存,既然可以免费使用它,为什么还要花时间将它返回给操作系统。
  • 你如何关闭(和打开)表单,它是否被任何东西释放?来源请。
  • 在不加载网页的情况下打开和关闭表单是否还有内存问题?
  • 您可以找到here 的此类泄漏应用程序示例。即使以TWebBrowser 作为组件的表单被释放,线程仍然在运行,并且每个新实例都会创建新的线程(因此内存消耗会增加)。我还没有找到解决方案,我尝试了很多方法,包括CoFreeUnusedLibrariesEx,导航到about:blank,没有任何帮助。这是一个严重的问题,因为创建多个表单实例会消耗大量系统资源。我的建议是隐藏表单,而不是发布,因为它似乎在这里没有效果。
  • 多年后,至今没有解决方案:/

标签: delphi delphi-2009 twebbrowser


【解决方案1】:

QC#106829 描述了 TWebBrowser 内存泄漏的一种可能原因。访问Document(以及通过TOleControl.GetIDispatchPropTOleControl.GetIUnknownProp 实现的任何其他属性)会导致泄漏,因为它调用AddRef 而没有调用Release。作为一种解决方法,您可以手动调用 Release,或者您可以修补 VCL (see here),或者您可以避免出现问题的属性(例如,使用 browser.DefaultInterface.Document 而不是 browser.Document)。

【讨论】:

  • 使用browser.DefaultInterface.Document 而不是browser.Document 解决了我的内存泄漏问题。谢谢
  • 请注意,这个 TOleControl 错误已在 Delphi 10.0 Seattle 中修复。
【解决方案2】:

使用 TWebBrowser 在幕后做了很多工作,与 Internet Explorer 的完整实例所做的大部分工作相同。它对你隐藏,但它仍然存在,我们可能无法强制从记忆中删除它。检查页面加载之前和之间的内存使用情况,并测试调用Navigate('about:blank'); 时会发生什么。还要检查你的析构函数是否被正确调用,并考虑从 OnClose 或 OnCloseQuery 调用Navigate('about:blank');。我发现这确实对记忆状况有所帮助。

【讨论】:

    【解决方案3】:

    最好的解决方案是停止使用 TWebbrowser。

    CEF4Delphi 是一个使用 Chrome 代替 Internet Explorer 的免费库。始终保持最新且非常高效:

    https://github.com/salvadordf/CEF4Delphi

    【讨论】:

      【解决方案4】:
      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}
      

      为了清除内存,我使用了这个功能,在论坛的某个地方找到。它比 SetProcessWorkingSetSize() 方法更清楚地清除“工作集”,但更难调用,它是在 Winapi.PsAPI 单元中注册的。 但是,我注意到这两个函数都清理了“工作集”。而如果你查看任务管理器中的“分配的内存”一栏,可以看到这个参数没有被清除。清理后我的应用程序的“工作集”可以减少到 10 MB,但所有分配的内存将保持等于 1.5 GB。而且,在我看来,这就是导致“内存不足”错误的原因。而且长时间看重度网站还是会出现这个错误。

      【讨论】:

        【解决方案5】:

        要释放内存,只需初始化新文档:

        (WebBrowser.Document as IPersistStreamInit).InitNew;
        

        【讨论】:

        • 这个办法不行,反正内存一直在增加。
        【解决方案6】:
        procedure TForm1.FreeMemory;
        begin
            if Win32Platform = VER_PLATFORM_WIN32_NT then
            SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
        end;
        

        时不时地调用它

        FreeMemory;
        

        【讨论】:

        • 此解决方案不起作用;它只是“压缩”使用的内存,但在新导航之后,之前使用的所有巨大内存都会再次分配。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-16
        • 2011-04-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多