Entwickler-Ecke
Internet / Netzwerk - Speicherfresser TWebBrowser¨?
sky21 - Fr 15.09.06 17:19
Titel: Speicherfresser TWebBrowser¨?
Hallo
Ich habe eine Instanz von TWebBrowser welche eine URL laden soll. Dieser Prozess wird N mal wiederholt. Der "Test" und damit auch die Instanz wird jedoch immer wieder neu erzeugt. Mit .free gebe ich natürlich die Instanz vorher wieder frei.
Trotzdem, meine Applikation frisst mächtig Speicher... immer und immer wieder und ich habe echt keine Ahnung, was los ist!
Interessant ist vielleicht dieses da:
Delphi-Quelltext
1: 2:
| FIEBrowser := TWebBrowser.Create(Mainform.tsWebBrowser); FIEBrowser.HostDockSite := MainForm.tsWebBrowser; |
Die "View" ist eingebettet.. d.h. die HTML seite wird dann im Sheet angezeigt. Kann es nun sein, dass dafür extra Speicher gebraucht wird und dann nicht mehr freigegeben wird? Wenn ja, wie kann ich den Speicher wieder freigeben?
Danke für hilfreiche Antworten
MrSaint - Fr 15.09.06 19:59
Hallo!
Wozu brauchst du das HostDockSite?
sky21 hat folgendes geschrieben: |
| Die "View" ist eingebettet.. d.h. die HTML seite wird dann im Sheet angezeigt. |
Bitte :?:
MrSaint
sky21 - Fr 15.09.06 20:07
MrSaint hat folgendes geschrieben: |
Hallo!
Wozu brauchst du das HostDockSite?
sky21 hat folgendes geschrieben: | | Die "View" ist eingebettet.. d.h. die HTML seite wird dann im Sheet angezeigt. |
Bitte :?:
MrSaint |
Damit die View dann eine von mir vorgegebene Grösse hat. (?). Habe nicht wirklich eine Erklärung dafür - ist nicht mein Code - muss ihn leider nur warten und den Memoryfehler beheben. Haste eine Idee woran das Speicherproblem liegen könnte?
MrSaint - Fr 15.09.06 20:23
Mir fehlt eine Definition der Begriffe "View" und "Sheet"...
Das HostDockSite würde ich persönlich durch "Parent" ersetzen... Okay, "Sheet" könnte ein TabSheet sein... Dann hast du den Webbrowser also in einem TabSheet. Okay. Aber warum erzeugst du ihn immer neu? reicht es nicht, den Webbrowser einmal in der IDE auf das TabSheet zu pflanzen und dann immer mit dieser einen Instanz zu arbeiten?
Dass der Webbrowser viel Speicher frisst, den er u.U. nicht mehr komplett freigibt könnte schon passieren... Das ist ja ein "Fremdprodukt", von dem du nicht genau weißt, wie sauber es geschrieben wurde (das ist im Endeffekt ja der IE von Microsoft, den du in deiner Anwendung hostest...).
MrSaint
sky21 - Mo 18.09.06 08:14
Hallo MrSaint
Korrekt, es ist ein TabSheet, welches die HTML Seite anzeigt. Kann dort nun gerade das Speicherproblem liegen? Diese wird ja immer nur aktualisiert, jedoch nie zerstört (während der Laufzeit).
Mit 'View' habe ich übrigends nur die darstellende Komponente gemeint. In meinem konkreten fall ist dies eben ein Tabsheet.
wulfskin - Mo 18.09.06 08:54
sky21 hat folgendes geschrieben: |
| Korrekt, es ist ein TabSheet, welches die HTML Seite anzeigt. Kann dort nun gerade das Speicherproblem liegen? Diese wird ja immer nur aktualisiert, jedoch nie zerstört (während der Laufzeit). |
Hallo,
das wird wohl das Problem sein. Wenn du die Objekte, die du zur Laufzeit erstellst, nicht während dieser freigibst, benötigt dein Programm unnötig viel Speicher. Was spricht dagegen, wie von MrSaint vorgeschlagen, nur eine Komponente zu benutzen? Ansonsten musst du dir die Komponenten wohl in einer globalen Variable merken und entsprechend freigeben!
Auch wenn Windows den Speicher am Programmende freigibt, gilt Grundsätzlich (ausgenommen DLL-Handles), dass man diese selber freigeben sollte, wenn man sie nicht mehr benötigt!
Gruß Hape!
sky21 - Mo 18.09.06 09:19
wulfskin hat folgendes geschrieben: |
sky21 hat folgendes geschrieben: | | Korrekt, es ist ein TabSheet, welches die HTML Seite anzeigt. Kann dort nun gerade das Speicherproblem liegen? Diese wird ja immer nur aktualisiert, jedoch nie zerstört (während der Laufzeit). | Hallo,
das wird wohl das Problem sein. Wenn du die Objekte, die du zur Laufzeit erstellst, nicht während dieser freigibst, benötigt dein Programm unnötig viel Speicher. Was spricht dagegen, wie von MrSaint vorgeschlagen, nur eine Komponente zu benutzen? Ansonsten musst du dir die Komponenten wohl in einer globalen Variable merken und entsprechend freigeben!
Auch wenn Windows den Speicher am Programmende freigibt, gilt Grundsätzlich (ausgenommen DLL-Handles), dass man diese selber freigeben sollte, wenn man sie nicht mehr benötigt!
Gruß Hape! |
Ja aber, ....
tsWebBrowser (meine darstellende Komponente) ist ein TTabSheet Das TabSheet wiederum ist eine VCL Komponente und gehört zu meiner MainForm. tsWebBrowser wird weder von mir (also mittels eigenem code) erstellt noch freigegeben. Aufgrund meines minimalistischen Delphikenntnisse behaupte ich nun, dass das GUI (also FormCreate/FormDestroy) diese Tätigkeiten für mich erledigt. Was passiert nun? Ich binde die WebBroweserinstanz an das TabSheet, lade eine komplette Hompage (HTML mit Bilder, ...) herunter. Der benötigte Speicher (sichtbar im Windows Task Manager wächst an). Die Files sind im Cache des IE - die Anzeige, also das TabSheet muss die heruntergeladenen Komponenten anzeigen. Ich nehme jetzt mal an, dass deshalb der Speicher angewachsen ist. So, ich lösche jetzt wieder den Cache und fange nochmals von vorne an (mit herunterladen einer Seite). Der Speicher wächst weiter. What the hell? Der IE kann ja schliesslich auch nicht nur EINE Seite herunterladen und dann ist fertig. hihi. Muss ich irgendwie den Content (aber wie?) im TabSheet zurücksetzen?
Hoffe auf Hilfe!
Edit:
Ich glaube, ich muss einfach auf irgend eine Weise den vom tsWebBrowser (TTabsheet) benötigten Speicher zur Anzeige der Daten wieder freigeben können.... wer weiss Rat?
alias5000 - Mo 18.09.06 11:56
Hallo,
könntest du uns bitte den relevanten Code der Komponente zeigen, der dieses verhalten verursachen könnte? (Zur not halt den ganzen, aber bitte kürze das raus, was absolut nicht relevant ist.
Gruß alias5000
sky21 - Mo 18.09.06 17:47
So, nach etlichen Stunden habe ich das Problem gefunden. Einen Workaround habe ich leider nicht... also hier kommts:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102:
| procedure MyBrowser.BrowserDocumentComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
var numOfImages, numOfFrames : integer; endTime : TDateTime; tp : integer; doc : IHTMLDocument2;
title : string; testsize : integer; retval: bool; size : Cardinal; browserControlInterface: IDispatch; NewURL : OleVariant; begin
FIEBrowser.OnDocumentComplete := nil; FIEBrowser.OnNewWindow2 := nil; FIEBrowser.OnNavigateError := nil;
numOfImages := 0; numOfFrames := 0; size := 0;
try doc := IHTMLDocument2(FIEBrowser.Document); except end;
try CalcSizeOfFrame(doc, testsize, numOfImages, numOfFrames); except end; end;
doc := nil;
LogInfo('Size: ' + IntToStr(size) + ' Bytes'); end;
procedure MyBrowser.CalcSizeOfFrame(htmlDocument: IHTMLDocument2; var totalBytes, numOfImages, numOfFrames: integer); var imageCollection: IHTMLElementCollection; image: HTMLImg; currentFrame, currentImage: integer; frameCollection: IHTMLFramesCollection2; frame: IHTMLDocument2; currentFrameVariant1, currentFrameVariant2: OleVariant; htmlWindow: IHTMLWindow2;
begin frameCollection := IHTMLFramesCollection2(htmlDocument.frames);
for currentFrame := 0 to frameCollection.Length - 1 do begin currentFrameVariant1 := currentFrame; currentFrameVariant2 := frameCollection.item(currentFrameVariant1); IDispatch(currentFrameVariant2).QueryInterface(IID_IHTMLWindow2, htmlWindow); if htmlWindow <> nil then begin try frame := IHTMLDocument2(htmlWindow.document); numOfFrames := numOfFrames + 1; CalcSizeOfFrame(frame, totalBytes, numOfImages, numOfFrames); except end; end; end;
imageCollection := IHTMLElementCollection(htmlDocument. images); for currentImage := 0 to imageCollection.length - 1 do begin image := HTMLImg(imageCollection.Item(currentImage, varEmpty)); if FImgList.IndexOf(image.nameProp) = -1 then begin totalBytes := totalBytes + StrToIntDef(image.filesize, 0); FImgList.Add(image.nameProp); end; numOfImages := numOfImages + 1; end;
frame := nil;
currentImage:=nil; end; |
Das Hauptproblem liegt bei 'doc'. Wenn ich dieses zuweise, und nach (oder auch gleich sofort) wieder auf nil setze, dann scheint der Speicher nicht freigegeben zu werden. Dumm nur, ich benötige das doc um die Funktion 'CalcSizeOfFrame' aufzurufen.
alias5000 - Mo 18.09.06 18:28
hmmm, aber eigentlich erstellst du doch gar keine neue Instanz, oder? Du benutzt doch nur das Webbrowser.Document, was bereits im Speicher erzeugt ist. Und mit der nil-Zuweisung setzt du doch auch nur einen Pointer auf nil, das Objekt wird nicht aus dem speicher gelöscht (was ja auch fatal wäre, da es zum WB gehört).
MrSaint - Mo 18.09.06 18:55
Falsch. doc ist ein Interface. Das wird automatisch zerstört, wenn es nichtmehr benötigt wird (also alle Variablen, die es benutzen auf nil gesetzt wurden). Der obige Code ist absolut in Ordnung, das geht nicht anders. versichere dich lieber, dass auch das FIEBrowser.Free aufgerufen wird (mit Breakpoints).
MrSaint
sky21 - Mo 18.09.06 20:49
Das Property "Document" gibt ein Interface zurück, welches man nicht explizit zerstören muss. D.h. doch, man muss einfach das Objekt (bei mir 'doc') auf nil setzen, dann wird es autmatisch freigegeben (aufgrund des internen reference counters oder so ähnlich).
Die Instanz FIEBrowser wird freigegeben. Hab ich schon im Debugger gecheked und gebe im Log auch eine Messagebox aus. Anderer Ansatz: Kann es eine Fehlimplementiertung in Delphi sein? (Benutzer Delphi v2005). Oder ist mein Datentyp 'doc' einfach sh**?
Interessanterweise sehe ich auch nichts mit dem FastMemoryManager, welcher eigentlich Memoryleaks finden sollte... und trotzdem. Das dingt stirbt mir weg, wenn kein Speicher mehr verfügbar ist.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!