[Delphi] Probleem met het vrijgeven van geheugen

Pagina: 1
Acties:

  • RwD
  • Registratie: Oktober 2000
  • Niet online

RwD

kloonikoon

Topicstarter
Ik heb een programma geschreven dat persberichten kan downloaden van websites. Dit wordt gedaan gebaseerd op een bepaald patroon in de url/bestandsnaam.
Gesimplificeerd heb ik 3 objecten gemaakt:
- een PressRelease object (PR)
afgeleide van een download object en kan een Persbericht downloaden, de html netjes formateren en opslaan
- een LinkPagina object (LP)
afgeleide van een download object en kan pagina's binnen halen waar links in zitten. De links worden doorgespeeld aan een LinkInterpreter
- een LinkInterpreter object (LI)
in staat links te evalueren om de beslissing te nemen een Persbericht object te maken voor download of een linkPagina voor links te rippen...

Dit werkt allemaal prima, LinkPagina maakt netjes een LinkInterpreter aan, welke dan weer PR of LP objecten maakt tot op een ingestelde scandiepte.
En ik krijg ook alles binnen wat ik hebben wil.

Echter na verloop van tijd tijdens het binnenhalen van de pagina's loopt het geheugengebruik steeds verder op, en soms zelfs met steeds grotere stappen en ik heb geen idee waarom...
Na het meelopen door de code zie ik dat iedere Free + nil opdracht netjes wordt uitgevoerd en op ieder punt in m'n programma er slechts één "tak" in het geheugen zou moeten zitten (dus 1 pad naar de plaats waar je dan bent, voorgaande pagina's die geheel gescanned zijn zijn ge-free-d)

Toch blijft ie geheugen vasthouden totdat hij klaar is met het binnenhalen van de persberichten. Zodra dat gebeurd is is het geheugenverbruik weer ongeveer bij het startpunt.

Nou heb ik rondgevraagd en iemand zei me dat het mogelijk is dat windows eventueel te kleine stukken geheugen niet meteen vrij geeft, maar dat is toch eigenlijk niet echt van toepassing hier? op een gegeven moment heb ik bijvoorbeeld een pagina 3 branches diep, waarvoor je geschat 1MB geheugen zou nodig hebben, waar het programma 150MB geheugen gebruikt. Als het programma gestart is gebruikt het pas 3MB

Iemand hier met een suggestie wat ik nog kan doen?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 23:06

Creepy

Tactical Espionage Splatterer

Je gebruikt de taskmanager om te kijken hoeveel geheugen je app gebruikt? Moet je voor de gein je app. eens minimaliseren :Y)

Als je echt denkt dat je app toch geheugen lekt terwijl je zeker weet dat alle benodigde free's e.d. worden aangeroepen (en ook objecten die in de constructor van een andere object worden aangemaakt ook worden vrijgegeven in de destructor van dat andere object!) dan zou je eens kunnen kijken naar tools zoals memproof.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Of zijn grote broertje AQTime

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

RwD schreef op 03 september 2004 @ 10:58:
Toch blijft ie geheugen vasthouden totdat hij klaar is met het binnenhalen van de persberichten. Zodra dat gebeurd is is het geheugenverbruik weer ongeveer bij het startpunt.
Er is toch geen probleem dan ? Dat je piekt op 150MB kan je misschien voorkomen door wat beter naar je ontwerp, misschien kan je een en ander
eerder "freeen". Of kijk eens welke stukken code in je objecten nu zoveel geheugen alloceren. Welk component gebruik je voor het downloaden van de pagina's, als je onderhuids bv. IE opstart kan ik me voorstellen dat er nogal wat geheugen benodigd is.

En anders heb ik wel een methode om door windows gereserveerde buffers vrij te geven (dit is hetzelfde als het "minimize" effect). Echter dit geeft weer eventuele performance problemen omdat windows iedere keer opnieuw die buffers gaat alloceren.
(ff uit het hoofd):
Delphi:
1
2
3
4
5
6
7
8
procedure MinimizeMemUsage;
var
  MyProcess, MemMin, MemMax : cardinal;
begin
   MyProcess := GetCurrentProcess();
  GetProcessWorkingSetSize(MyProcess, MemMin, MemMax);
  SetProcessWorkingSetSize(MyProcess, MemMin, MemMax);
end;

[ Voor 15% gewijzigd door Verwijderd op 03-09-2004 12:19 ]


  • RwD
  • Registratie: Oktober 2000
  • Niet online

RwD

kloonikoon

Topicstarter
Creepy schreef op 03 september 2004 @ 11:03:
Je gebruikt de taskmanager om te kijken hoeveel geheugen je app gebruikt? Moet je voor de gein je app. eens minimaliseren :Y)

Als je echt denkt dat je app toch geheugen lekt terwijl je zeker weet dat alle benodigde free's e.d. worden aangeroepen (en ook objecten die in de constructor van een andere object worden aangemaakt ook worden vrijgegeven in de destructor van dat andere object!) dan zou je eens kunnen kijken naar tools zoals memproof.
Minimaliseren :?
Owkeeeej...
Waarom dropt ie van 100MB naar 60MB iedere keer dat ik bij ongeveer 100 minimaliseer. Heb ik soms een stomme fout begaan??

Memproof is een beetje waardeloos voor mij, weet niet wat ik ermee doen moet. Ik zie alleen maar enorm veel pointer gereserveerd worden, met bijbehorend geheugen, en op het einde (maar ook tussendoor) zijn ze weer vrij gegeven. (Betekend dat overigens dat hij dus idd zoals ik zeg uiteindelijk alles vrij geeft?)
Verwijderd schreef op 03 september 2004 @ 12:15:
[...]
Er is toch geen probleem dan ? Dat je piekt op 150MB kan je misschien voorkomen door wat beter naar je ontwerp, misschien kan je een en ander
eerder "freeen". Of kijk eens welke stukken code in je objecten nu zoveel geheugen alloceren. Welk component gebruik je voor het downloaden van de pagina's, als je onderhuids bv. IE opstart kan ik me voorstellen dat er nogal wat geheugen benodigd is.

En anders heb ik wel een methode om door windows gereserveerde buffers vrij te geven (dit is hetzelfde als het "minimize" effect). Echter dit geeft weer eventuele performance problemen omdat windows iedere keer opnieuw die buffers gaat alloceren.
(ff uit het hoofd):
Delphi:
1
2
3
4
5
6
7
8
procedure MinimizeMemUsage;
var
  MyProcess, MemMin, MemMax : cardinal;
begin
   MyProcess := GetCurrentProcess();
  GetProcessWorkingSetSize(MyProcess, MemMin, MemMax);
  SetProcessWorkingSetSize(MyProcess, MemMin, MemMax);
end;
Hij piekt niet op 150, het gaat gewoon door... En hoe langer het duurt hoe harder het gaat... Toch, ik heb de code 100den keren doorlopen, object wordt gecreeerd, doet zn ding en wordt (na de creatie en uitvoering dus) met .Free en nil dood geslagen binnen een try finally block...
Hij kan geen gekke extra dingen creeeren, de LI kan slechts 1 object per link aanmaken, en zodra een PR gedownload en opgeslagen heeft wordt ie vernietigd...

Ik weet niet precies hoe ik je procedure precies moet gebruiken (gewoon aanroepen als ik even wat wil schuiven met het geheugen?). Ik weet zelf niet eens hoeveel geheugen ik nodig heb voor het bovenstaande. Gezien de gegevens die daadwerkelijk bijgehouden worden (een html pagina (van een paar KB) wordt gedownload en in het geheugen gepropt, nog een paar korte strings en variabelen) Zou ik zeggen dat het hooguit een paar MB mag zijn en heeel hoog ingeschat misschien 20MB maar nooit 150 of meer...

Ow, om wat specifieker antwoord te geven:
Ik gebruik IdHTTP (de laatste versie) voor het binnenhalen van de bestanden
Het meeste geheugen wordt gebruikt door de PP en LP objecten afhankelijk van hoe groot de gedownloade pagina's zijn.

[ Voor 7% gewijzigd door RwD op 03-09-2004 12:37 ]


  • RwD
  • Registratie: Oktober 2000
  • Niet online

RwD

kloonikoon

Topicstarter
Verwijderd schreef op 03 september 2004 @ 12:15:
En anders heb ik wel een methode om door windows gereserveerde buffers vrij te geven (dit is hetzelfde als het "minimize" effect). Echter dit geeft weer eventuele performance problemen omdat windows iedere keer opnieuw die buffers gaat alloceren.
(ff uit het hoofd):
Delphi:
1
2
3
4
5
6
7
8
procedure MinimizeMemUsage;
var
  MyProcess, MemMin, MemMax : cardinal;
begin
   MyProcess := GetCurrentProcess();
  GetProcessWorkingSetSize(MyProcess, MemMin, MemMax);
  SetProcessWorkingSetSize(MyProcess, MemMin, MemMax);
end;
Ik heb het even in een testprogramma geprobeerd:
van 2,8MB --> 1,5MB
Het doet dus wel iets goeds :)

Echter, na minimizen ging het van 1,5MB naar 0,7MB.
Waarom is het geheugenbeheer zo dat een programma ongebruikt geheugen gereserveerd heeft??? En kan ik het minimize effect reproduceren zonder te minimizen?

Edit:
Ik heb je procedure in het programma gedaan, en na geruime tijd downloaden heeft ie voorlopig gepiekt op 120MB en blijft redelijk constant rond de 87MB schommelen. Nu heb ik in ieder geval het grootste probleem niet meer; dat ie op een gegeven moment alles bezet houdt. Wel ben ik nog steeds geinteresseerd in andere suggesties om het probleem te kunnen analyseren en oplossen!!

[ Voor 25% gewijzigd door RwD op 03-09-2004 13:10 ]


  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02-2025

SchizoDuckie

Kwaak

't is alweer een tijdje geleden dat ik delphi gedaan heb, maar gebruik je misshcien 3rd party objecten om de pages binnen te halen die deze pointers zouden kunne reserveren?

Stop uploading passwords to Github!


  • Eegee
  • Registratie: Januari 2000
  • Laatst online: 21:50
RwD schreef op 03 september 2004 @ 12:29:
[...]
Memproof is een beetje waardeloos voor mij, weet niet wat ik ermee doen moet. Ik zie alleen maar enorm veel pointer gereserveerd worden, met bijbehorend geheugen, en op het einde (maar ook tussendoor) zijn ze weer vrij gegeven. (Betekend dat overigens dat hij dus idd zoals ik zeg uiteindelijk alles vrij geeft?)
Je moet na het draaien van je programma via Memproof onder Resource Details (Resource View: unfreed resources) kijken, als daar nog veel live pointers staan o.i.d. dan wordt niet alles gefree'd. Dat lijstje zou je zo klein mogelijk moeten zien te krijgen.

  • RwD
  • Registratie: Oktober 2000
  • Niet online

RwD

kloonikoon

Topicstarter
Ik free alles zodra ik het niet meer nodig heb, het programma werkt alsof je een directoriestructuur linksom doorloopt; zodra je er rechts langs gaat free je het.

Overigens met die wijziging loopt het programma veeeeel langer voordat het fout gaat, maar uiteindelijk gebruikt ie toch 164 MB ongeveer...

[ Voor 3% gewijzigd door RwD op 03-09-2004 13:57 ]


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Dat met die MinimizeMemUsage is alleenmaar jezelf voor de gek houden en de optimalizatie van windows buitenspel zetten. Het is symptoombestrijding. Geen goed idee dus. Probeer de oorzaak te vinden en bedenk daar een oplossing voor.

We adore chaos because we like to restore order - M.C. Escher


  • RwD
  • Registratie: Oktober 2000
  • Niet online

RwD

kloonikoon

Topicstarter
LordLarry schreef op 03 september 2004 @ 14:00:
Dat met die MinimizeMemUsage is alleenmaar jezelf voor de gek houden en de optimalizatie van windows buitenspel zetten. Het is symptoombestrijding. Geen goed idee dus. Probeer de oorzaak te vinden en bedenk daar een oplossing voor.
Dat dacht ik dus ook toen ik het er in zette ivm eerder gelezen stukken over het geheugenbeheer en waarom je photoshop de eerste keer in 9 seconden op kunt starten, maar dat het de tweede keer korter duurt.

Maar met die functie draait het wel langer en komt het verder dan zonder...

Heb je dan geen enkel idee waar het aan kan liggen? ik probeer dit stuk code al een half jaar te debuggen, en alles wat gereserveerd wordt dat wordt ook daadwerkelijk vrij gegeven zodra je het niet meer kunt gebruiken. Zoals zo'n left traversal hoe ik dat eerst uitlegde....

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

We zullen eerst de oorzaak van het geheugengebruik moeten vinden. Als je dat goed wil doen moet je de juiste tools gebruiken. De TaskManager is niet de juiste. Ik stel voor dat je AQTime eens uitprobeert. Deze kan je o.a. zeer precies vertellen welke classes waar gecreerd worden. Hoeveel geheugen dat kost. Hoeveel er weer vrijgegeven worden. Hoeveel er maximaal gecreerd zijn op een bepaald punt enz...

Op basis van die gegevens zou je moeten kunnen zien of er geheugen lekt of dat je datastructuren nu eenmaal zo groot worden. Pas dan kan je gericht aan een oplossing werken.

Verder zou het helpen als je je meer verdiept over het geheugen beheer van Windows en van Delphi. Delphi heeft namelijk zijn eigen memory manager die het geheugen van windows reserveerd wanneer dat nodig is. Als er geheugen in Delphi wordt vrijgegeven wordt het niet meteen teruggegeven aan Windows, maar wordt er getracht deze te hergebruiken. Geheugenbeheer in Windows werkt namelijk relatief langzaam als je elk klein stukje geheugen direct weer terug zou geven aan windows of te gaan reserveren. Daarnaast kan Delphi's geheugen manager ook gefragmenteerd raken bijvoorbeeld. Er zijn ook vervangers voor Delphi's geheugen manager als je denkt dat dat het probleem is. Hieronder kan je er een paar vinden. Overigens blijkt uit praktijktests dat Delphi's geheugenmanager over het gemiddeld gezien erg goed is. De alternatieven zijn vaak alleen maar beter op bepaalde gebieden.

http://www.codexterity.com/fastsharemem.htm
http://glscene.sourceforge.net/oldnews2004.htm http://prdownloads.source...cyclerMM-1.0.zip?download
http://www.nexusdb.com/index.asp?id=77
http://www.digitaltundra.com/bigbrainpro.php
http://bdn.borland.com/homepages/dsp/newl/d50/f014_001.htm
http://codecentral.borlan...cweb.exe/listing?id=14283

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

LordLarry schreef op 03 september 2004 @ 14:00:
Dat met die MinimizeMemUsage is alleenmaar jezelf voor de gek houden en de optimalizatie van windows buitenspel zetten. Het is symptoombestrijding. Geen goed idee dus. Probeer de oorzaak te vinden en bedenk daar een oplossing voor.
Ik zelf ben er ook geen voorstander van, maar sommige mensen krijg je niet aan de 't verstand dat die tasmanager geen goede voorstelling geeft van het "geheugen management" van een applicatie. Dan gooi je deze "smerige truc" er overheen, en ze zien het goede resultaat in de taskmanager. Let wel, dat echt foutief gealloceerd/niet vrijgegeven geheugen hierdoor ook niet zomaar wordt vrijgegeven.
RwD schreef op 03 september 2004 @ 15:34:
[...]
Heb je dan geen enkel idee waar het aan kan liggen? ik probeer dit stuk code al een half jaar te debuggen, en alles wat gereserveerd wordt dat wordt ook daadwerkelijk vrij gegeven zodra je het niet meer kunt gebruiken. Zoals zo'n left traversal hoe ik dat eerst uitlegde....
Dit is zeer moeilijk te beantwoorden zonder inzicht in de code, vaak komt het neer op f8'en door de code heen. En idd eerst zoveel mogelijk proberen te analyseren met de juiste tools (waarvan er al een paar in het topic genoemd zijn).

Een opsomming van de door jouw gebruikte componenten (van derden), kan misschien al inzage geven in het geheugen gebruik.

Ik vind het wel raar dat jouw programma aan piek geheugen zoveel gebruikt, bij een "simpele inzet". Verder geef je ook geen inzage in wat voor soort gebruik je deze geheugen pieken krijgt (hoeveel pages parse je bv)? Welke Delphi versie gebruik je (in wat oudere versie, kan je bv geheugen problemen krijgen als je gebruikt maakt van TCollection/TCollectionitem descendants)

[ Voor 54% gewijzigd door Verwijderd op 04-09-2004 00:40 ]


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 23:27

Tomatoman

Fulltime prutser

Als je al zo veel moeite hebt genomen, kun je ook proberen de webbot in je programma in een aparte thread onder te brengen. Als de bot alle pagina's heeft doorlopen, controleer je hoeveel geheugen de thread in beslag neemt (natuurlijk vooraf ook meten). Nu weet je of er veel geheugen blijft 'hangen'. Vrijgeven van de thread zou het probleem dan moeten oplossen.

Het voordeel van deze arbeidsintensieve benadering is (1) dat je het geheugen geforceerd kunt vrijgeven door simpelweg de thread de nek om te draaien en (2) dat je tijdens het monitoren van het gebruikte geheugen echt alleen de webbot bekijkt en niet ook nog eens de gebruikersinterface, objecten op de achtergrond en alle andere dingen die worden meegecompileerd.

Verder kun je jezelf de vraag stellen of 100 MB geheugengebruik echt wel zo erg is. Vergis je niet in de werkelijke hoeveelheid geheugen die een standaard Officeapplicatie in beslag neemt. Dat is niet alleen de grootte die de Excel of Word executable inneemt, maar ook allerlei helper processen en achtergrondservices. Niemand vindt dat Word onacceptabel groot is. Wat ik hiermee probeer aan te geven is dat er zonder dat je het je realiseert nog veel meer programma's op je computer staan die 'zomaar' 100 MB aan geheugen in gebruik kunnen nemen.

[ Voor 7% gewijzigd door Tomatoman op 05-09-2004 16:48 ]

Een goede grap mag vrienden kosten.


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Bovendien is die 100Mb Virtueel Geheugen. Dat omvat wellicht mem pages die gedeeld worden met andere processen (DLLs), naar de pagefile weggeswapped geheugen, enz. En waarschijnlijk maar een relatief klein deel echt RAM geheugen.

We adore chaos because we like to restore order - M.C. Escher

Pagina: 1