Как освободить память, используемую IHTMLDocument?

есть ли способ освободить память после использования IHTMLDocument (IHTMLDocument2)?

В настоящее время я использую функцию EmptyWorkingSet но я чувствую, что это не лучший способ сделать это

EmptyWorkingSet(GetCurrentProcess);

Даже освобождение TWebBrowser не помогает; проблема, похоже, в COM-классе IHTMLDocument, который не освобождается из памяти. Есть ли четкий способ выпустить его; что-то вроде 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;

Вы будете видеть потерю памяти после каждого освобождения веб-браузера. Когда я запускаю свой JavaSrcipt, он намного превышает 300 КБ, это около 1 МБ, и это может вызвать утечку памяти, если я запускаю это много раз.

Большое спасибо


person Community    schedule 18.05.2011    source источник
comment
EmptyWorkingSet фактически не освобождает память. Он просто выгружает активную память на диск. Ваш процесс по-прежнему владеет этой памятью; доступ к нему вернет его обратно в ОЗУ. Как вы измеряете потребление памяти вашим процессом и что заставляет вас думать, что вам вообще нужно решить проблему?   -  person Rob Kennedy    schedule 19.05.2011
comment
Я использую только стандартный диспетчер задач Windows. Я работаю со своим скриптом GoogleMaps, и когда я попадаю в StreetView, рабочий набор (как он, вероятно, называется в английской версии Windows) увеличивается до 300 МБ, и, похоже, он остается там.   -  person    schedule 19.05.2011
comment
Возможно, важен порядок? Попробуйте сначала присвоить nil HTMLDocument и затем освободить WebBrowser. Другая (возможно, не связанная с этим) вещь: WebBrowser.Document может не содержать действительного IHtmlDocument2 сразу после Navigate (страница может все еще загружаться). Вероятно, вам следует использовать событие типа OnDocumentComplete.   -  person Ondrej Kelle    schedule 19.05.2011
comment
Просто идея: может быть, даже попробовать Navigate('about:blank') перед освобождением.   -  person Ondrej Kelle    schedule 19.05.2011
comment
@TOndrej - это именно то, что я сделал; для ожидания загрузки документа я пробовал оба - событие OnDocumentComplete и ожидание TWebBrowser.ReadyState = READYSTATE_COMPLETE в цикле, поэтому должен быть действительный документ. И Navigate('about:blank') не помогает, хотя он может как-то освободить документ, но должен быть такой кеш для перехода на предыдущую страницу. Но спасибо за идеи.   -  person    schedule 19.05.2011
comment
Еще одна идея: я помню, что у меня была аналогичная проблема с внепроцессным COM-классом и CoFreeUnusedLibrariesEx решил эту проблему.   -  person Ondrej Kelle    schedule 19.05.2011
comment
Вот и все; вот что я искал! Большое спасибо ! Вызов CoFreeUnusedLibrariesEx(0, 0); освобождает большой блок памяти сразу после использования WebBrowser.   -  person    schedule 19.05.2011
comment
Спасибо, я рад, что смог помочь! :-)   -  person Ondrej Kelle    schedule 19.05.2011


Ответы (4)


Обычно классы COM следует освобождать, когда вы освобождаете все ссылки на них. Обычно это можно сделать, присвоив nil всем переменным, содержащим ссылки на их интерфейсы.

Для немедленного высвобождения памяти, используемой COM-DLL, вы можете использовать CoFreeUnusedLibrariesEx.

person Ondrej Kelle    schedule 18.05.2011
comment
Вот что я пробовал, но это не помогает. Может мне просто нужен измеритель памяти получше. Единственное, что я знаю, это то, что когда я вызываю EmptyWorkingSet, память уменьшается (путем подкачки на мой диск, как сказал Роб), но эта часть размером 300 МБ исчезает. - person ; 19.05.2011
comment
Я думаю, либо вы не выпускаете все ссылки, либо вы обнаружили ошибку (в самом элементе управления IE или уровне Delphi / COM). Сначала проверьте свой собственный код. - person Ondrej Kelle; 19.05.2011
comment
Долго искал причину, но толкового решения не нашел. В моем скрипте со многими экземплярами, использующими Google StreetView, память увеличивается до упомянутых 300 МБ, и я не могу вернуть ее, даже если я указываю HTMLDocuments равным нулю. Я не могу привести здесь этот сценарий, но даже если вы попробуете код, который я вставил, вы потеряете около 300 КБ с каждым экземпляром. +1 за ответ все равно :) - person ; 19.05.2011

Я не знаю Delphi, но я работал с IHTMLDocument на C ++. Я считаю, что вам нужно вызвать метод Release (). Я также знаю, что он использует BSTR для строк, так что это может быть еще одно место для ищите память, которая не освобождается.

person daalbert    schedule 18.05.2011
comment
Delphi автоматически вызывает Release для указателей интерфейса. Не вызывайте это вручную. (Это немного похоже на CComPtr из ATL.) Аналогичным образом, BSTR представлен в Delphi типом WideString, а RTL автоматически управляет временем их жизни, как и любые другие строки. - person Rob Kennedy; 19.05.2011

Вы пробовали Navigate ('about: blank'); перед освобождением? Это уже должно освободить некоторую память. Я также думаю, что внутренняя часть WebBrower (которая примерно такая же, как и Internet Explorer) хранит много вещей в памяти, просто для того, чтобы служить историей и кешем для любого другого TWebBrowser (или IWebBrowser2, чтобы быть более конкретно), что может существовать в этом сеансе исполняемого файла даже в (ближайшем) будущем.

Если повезет (и если вы используете Navigate или Navigate2), вы можете изменить это, если вызовете с помощью такие флаги, как navNoHistory, navNoWriteToCache и, возможно, другие.

person Stijn Sanders    schedule 19.05.2011
comment
+1; тоже выглядит многообещающе; Я проверю это. Моя самая большая проблема решила CoFreeUnusedLibrariesEx, но это правда, что он не выпускает все. Спасибо ! - person ; 19.05.2011

Эта проблема мучит пользователей TWebbrowser целую вечность, и пока нет решения; единственный способ освободить память, используемую TWebbrowser, - это закрыть приложение и снова открыть его.

person delphirules    schedule 11.06.2015