Как да освободим паметта, използвана от IHTMLDocument?

има ли начин да освободите памет след използване на 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;

Ще видите как паметта се губи след всяко освобождаване на уеб браузър. Когато стартирам моя JavaSrcipt, той е дори повече от 300 kB, това е около 1 MB и това може да причини изтичане на памет, в случай че изпълнявам това много пъти.

Благодаря много


person Community    schedule 18.05.2011    source източник
comment
EmptyWorkingSet всъщност не освобождава памет. Той просто прехвърля активната памет на диск. Вашият процес все още притежава тази памет; достъпът до него ще го върне обратно в RAM. Как измервате потреблението на памет от вашия процес и какво ви кара да мислите, че изобщо имате проблем за отстраняване?   -  person Rob Kennedy    schedule 19.05.2011
comment
Използвам само стандартния Windows TaskManager. Работя с моя скрипт на GoogleMaps и когато вляза в StreetView, работният набор (както вероятно се нарича в английската версия на Windows) се увеличава до 300 MB и изглежда, че остава там.   -  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 класовете обикновено трябва да бъдат освободени, когато освободите всички препратки към тях. Обикновено това може да стане чрез присвояване на нула на всички променливи, съдържащи препратки към техните интерфейси.

За незабавно освобождаване на паметта, използвана от COM DLL, можете да използвате CoFreeUnusedLibrariesEx.

person Ondrej Kelle    schedule 18.05.2011
comment
Това съм пробвал, но не помага. Може би просто ми трябва по-добър измервател на паметта. Единственото нещо, което знам е, че когато извикам EmptyWorkingSet, паметта намалява (чрез страниране на моя диск, както спомена Роб), но тази част от 300 MB изчезва. - person ; 19.05.2011
comment
Мисля, че или не пускате всички препратки, или сте открили грешка (в самата контрола на IE или слоя Delphi/COM). Първо проверете собствения си код. - person Ondrej Kelle; 19.05.2011
comment
Дълго време търся причината, но не намирам разумно решение. С моя скрипт с много екземпляри, използващи StreetView на Google, паметта се увеличава до споменатите 300 MB и не мога да я върна, дори ако насоча HTMLDocuments към нула. Не мога да дам тук този скрипт, но дори и да опитате кода, който съм поставил, ще загубите около 300 kB с всяко копие. +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