| Autor |
Beitrag |
HenryHux
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Fr 08.10.10 12:03
Hi,
ich habe immoment ein Programm, dass Bitmaps aufeinander vergleicht.
Läuft alles gut, aber nach 10Minuten hat der Prozess schon über 200Mb Ram gefressen und irgendwann bricht es dann ab aufgrund von Resourcen-Mangel.
Wodran könnte das liegen?
Lg
Henry
|
|
platzwart
      
Beiträge: 1054
Erhaltene Danke: 78
Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
|
Verfasst: Fr 08.10.10 12:05
Naja, das liegt wohl daran, dass du ein Bild in den RAM lädst, es vergleichst und dann das nächste laädst, ohne das vorherige aus dem RAM zu löschen. So häufen sich die Bilder an und irgendwann ist der RAM voll...
_________________ Wissenschaft schafft Wissenschaft, denn Wissenschaft ist Wissenschaft, die mit Wissen und Schaffen Wissen schafft. (myself)
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Fr 08.10.10 12:09
Ok, und wie werden die Bilder aus dem RAM gelöscht?
Mit imagex.free?
|
|
platzwart
      
Beiträge: 1054
Erhaltene Danke: 78
Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
|
Verfasst: Fr 08.10.10 12:10
Das wäre schon mal ein guter Ansatz  Wenn du ein wenig deines Quellcodes zeigen würdest, könnte man da genauere Angaben machen.
_________________ Wissenschaft schafft Wissenschaft, denn Wissenschaft ist Wissenschaft, die mit Wissen und Schaffen Wissen schafft. (myself)
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Fr 08.10.10 12:18
Ok, also die Bitmaps werden zuerst geshootet, dann geschnitten und anschließend verglichen.
Dazu folgende Funktionen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Procedure Screenshot(image:Timage;Bounds:TRect;Faktor:Double); var DeskCanvas: TCanvas; begin DeskCanvas := TCanvas.Create; DeskCanvas.Handle := GetDC(0); image.Width := Round((Bounds.Right - Bounds.left) * Faktor); image.Height := Round((Bounds.Right - Bounds.Left) * Faktor); Image.Canvas.CopyRect(Image.ClientRect, DeskCanvas, Bounds); DeskCanvas.Free; end; |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure Schneiden(Links, Rechts, Oben, Unten, z1, z2 : Integer); var SourceBitmap : TBitmap; TargetBitmap : TBitmap; Cut : TRect; begin SourceBitmap:=Tbitmap.Create; TargetBitmap:=Tbitmap.Create; SourceBitmap.LoadFromFile(Path+'image'+inttostr(z1)+'.bmp'); Cut.Left := Links; Cut.Top := Oben; Cut.Right := Rechts; Cut.Bottom := Unten;
TargetBitmap.Width := Cut.Right - Cut.Left; TargetBitmap.Height := Cut.Bottom - Cut.Top; Sleep(50); Application.ProcessMessages; BitBlt(TargetBitmap.Canvas.Handle, 0, 0, Cut.Right, Cut.Bottom, SourceBitmap.Canvas.Handle, Cut.Left, Cut.Top, SRCCOPY); SourceBitmap.Canvas.Refresh; TargetBitmap.SaveToFile(Path+'image'+inttostr(z2)+'.bmp'); end; |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function CompareImages(Bitmap3, Bitmap2: TBitmap): LongWord; var xy: integer; P1, P2: PInteger; begin Result:=0; Bitmap3.PixelFormat:=pf32bit; Bitmap2.PixelFormat:=pf32bit; P1:=Bitmap3.ScanLine[Bitmap3.Height-1]; P2:=Bitmap2.ScanLine[Bitmap2.Height-1]; for xy:=1 to Bitmap3.Height*Bitmap3.Width do begin Inc(Result, Byte(P1^<>P2^)); Inc(P1); Inc(P2); end; end; |
Anschließend aufgerufen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| Screenshot(image1,Rect(Breite,Hoehe,Breite + Breite2,Hoehe + Hoehe2),Faktor); Image1.Picture.SaveToFile (Path+'image'+inttostr(z1)+'.bmp'); schneiden(30,43,64,100,1,2); EinBild:= Tbitmap.create; NochEinBild:= Tbitmap.create; image2.picture.loadfromfile(Path+'image'+inttostr(z2)+'.bmp'); EinBild.LoadFromFile(Path+'image2.bmp'); for i := 1 to 20 do begin NocheinBild.LoadFromFile(Path+'Ordner1\'+'K'+inttostr(i)+'.bmp'); Diff := CompareImages(EinBild, NocheinBild); |
und am Ende der Prozedur:
Delphi-Quelltext 1: 2:
| EinBild.Free; NochEinBild.Free; |
Ich dachte eigentlich, dass der Speicher durch die letzten Zeilen wieder freigegeben würde, aber anscheinend doch nicht.
Lg
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Fr 08.10.10 12:21
Und wo werden die die Bitmaps in der Prozedur Schneiden wieder freigegeben?
Zuletzt bearbeitet von Luckie am Fr 08.10.10 12:31, insgesamt 1-mal bearbeitet
|
|
platzwart
      
Beiträge: 1054
Erhaltene Danke: 78
Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
|
Verfasst: Fr 08.10.10 12:24
Delphi-Quelltext 1: 2:
| SourceBitmap.Free; TargetBitmap.Free; |
... und alles sollte laufen.
_________________ Wissenschaft schafft Wissenschaft, denn Wissenschaft ist Wissenschaft, die mit Wissen und Schaffen Wissen schafft. (myself)
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Fr 08.10.10 12:32
Und ein Ressourcenschutzblock könnte auch nicht schaden. Und was soll das: Delphi-Quelltext 1: 2:
| Sleep(50); Application.ProcessMessages; |
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Fr 08.10.10 12:33
Ok, danke hatte ich vergessen.
Steigt jetzt zwar wesentlich langsamer, aber trotzdem steigt er noch und das Programm denke hat nach 20min auch an die 30mb erreicht.
Ich lasse ihn atm nur in dieser Schleife laufen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| repeat bitmap1:=0; bitmap2:=0; bitmap3:=0; bitmap4:=0; getbitmap1.Click; getbitmap2.click; getbitmap3.Click; getbitmap4.Click; wait(500); until (bitmap1>0) and (bitmap2>0) and (bitmap3>0) and (bitmap4>0); |
Wie gesagt, diese getbitmaps werden nur durch den oben genannten Aufruf aufgerufen.
Muss ich den RAM Anspruch in Kauf nehmen, oder habe ich noch etwas übersehen?
Lg
Edit:
Luckie hat folgendes geschrieben : | Und ein Ressourcenschutzblock könnte auch nicht schaden. Und was soll das: Delphi-Quelltext 1: 2:
| Sleep(50); Application.ProcessMessages; | |
Er soll die Bilder auf Veränderungen prüfen und da dachte ich mir, es wäre besser ihn nicht durchgängig laufen zu haben, sondern den Prozess ein bisschen langsamer laufen zu lassen.
Henry
|
|
Flamefire
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Fr 08.10.10 12:43
Lade dir mal FastMM4 runter und binde das als 1. Unit im Projekt ein. (Also im Projekt auf Quelltext anzeigen klicken. Dass muss wirklich da rein, wo Application.CreateForm usw steht)
Dann rufe deine Prozeduren einmal auf und beende danach immer das Programm. FastMM sagt dir dann, wo Memleaks aufgetreten sind. Mach das mit jeder Prozedur, bis du den Fehler gefunden hast.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Fr 08.10.10 12:47
Für regelmäßig auszuführende Tätigkeiten gibt's Timer
Weiter gehören interne Daten (Zwischengespeicherte Bilder) nicht in ein TImage (generell nicht in visuelle Komponenten der VCL).
Ressourcen-Schutzblöcke könnten deinem Source wirklich nicht schaden.
Lass mal FastMM4 mit aktivierter Memory Leak Detection laufen.
Was sollen deine Canvas.Refresh-Aufrufe?
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Sa 09.10.10 11:10
Ok, Danke habe nen paar Schen jetzt geändert.
Aber leider komme ich mit FastMM4 nicht ganz klar.
Bei jedem kompilieren bekomme ich diese Meldung:
---------------------------
Read1.exe: Cannot install FastMM4 - Memory has already been allocated
---------------------------
FastMM4 cannot install since memory has already been allocated through the default memory manager.
FastMM4.pas MUST be the first unit in your project's .dpr file, otherwise memory may be allocated
through the default memory manager before FastMM4 gains control.
If you are using an exception trapper like MadExcept (or any tool that modifies the unit initialization order),
go into its configuration page and ensure that the FastMM4.pas unit is initialized before any other unit.
---------------------------
OK
---------------------------
Wenn es daran liegt, dass ich FastMM4 nicht als erste Unit habe, wie könnte ich das denn dann machen?
Lg
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Sa 09.10.10 11:27
HenryHux hat folgendes geschrieben : | Ok, Danke habe nen paar Schen jetzt geändert.
Aber leider komme ich mit FastMM4 nicht ganz klar.
Bei jedem kompilieren bekomme ich diese Meldung:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| --------------------------- Read1.exe: Cannot install FastMM4 - Memory has already been allocated --------------------------- FastMM4 cannot install since memory has already been allocated through the default memory manager.
FastMM4.pas MUST be the first unit in your project's .dpr file, otherwise memory may be allocated
through the default memory manager before FastMM4 gains control.
If you are using an exception trapper like MadExcept (or any tool that modifies the unit initialization order),
go into its configuration page and ensure that the FastMM4.pas unit is initialized before any other unit. --------------------------- OK --------------------------- | |
Bitte Code-Blöcke für sowas
HenryHux hat folgendes geschrieben : | Wenn es daran liegt, dass ich FastMM4 nicht als erste Unit habe, wie könnte ich das denn dann machen?
Lg |
Ich wiederhole mal:
Flamefire hat folgendes geschrieben : | | Lade dir mal FastMM4 runter und binde das als 1. Unit im Projekt ein. (Also im Projekt auf Quelltext anzeigen klicken. Dass muss wirklich da rein, wo Application.CreateForm usw steht) |
Oder noch mal zum Mitmeißeln:
Oben im Menü auf Projekt --> Quelltext anzeigen
Dort dürfte ein Fenster mit "project XYZ;" in der ersten Zeile aufgehen.
Dort als erste Unit in der Uses FastMM4 eintragen.
Bei aktuellen Delphi-Versionen kannst Du den Speichermanager auch über Projekt-->Optionen einstellen.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Sa 09.10.10 11:48
Ok, danke habe ihn so zum Laufen bekommen.
Habe die Schleife einmal laufen lassen und Progg beendet.
Es kam:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| --------------------------- Read1.exe: Memory Leak Detected --------------------------- This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):
61 - 68 bytes: TBitmap x 2
117 - 124 bytes: TBitmapImage x 2
Note: To obtain a log file containing detail on memory leaks, enable the "FullDebugMode" and "LogMemoryLeakDetailToFile" conditional defines. To disable this memory leak check, undefine "EnableMemoryLeakReporting".
--------------------------- OK --------------------------- |
Ich wusste nicht genau, wie ich den FullDebugMode aktivieren kann, habs einfach mal hiermit versucht, hatte sich aber auch nicht viel verändert.
Delphi-Quelltext 1: 2:
| FullDebugModeScanMemoryPoolBeforeEveryOperation: Boolean = true; FullDebugModeRegisterAllAllocsAsExpectedMemoryLeak: Boolean = true; |
Kann man in den Informationen schon iwas erkennen?
Lg
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Sa 09.10.10 11:53
Im Verzeichnis mit der EXE dürfte sich nun eine Logfile befinden. Schau dort mal rein. Da sollten Zeilennummern stehen, wo die Bitmaps herkommen.
Zum Aktivieren des Full Debug Modes: Schau mal in die FastMM4.pas rein. Da dürfte es eine ausführliche Beschreibung geben.
Ach ja: Hast Du mal aktualisierte Sources für uns? Bitte die Routinen soweit es geht vollständig, die aufgerufen werden.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Sa 09.10.10 11:59
So, endlich klappt es.. Danke!
Tja falsche Bitmaps in ein paar Prozeduren freigegeben, d.h ein paar wurden nicht wieder freigegeben.
Kommt von copy pasting
Aber zu den Resourcen-Schutzblöcken die ihr angesprochen habt, was genau bringen die?
Hab mir das mit try-finally und try-exept mal angeguckt.
Was bringt es mir etwas einzubauen was sowieso ausgeführt wird?
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:
| begin try SourceBitmap:=Tbitmap.Create; TargetBitmap:=Tbitmap.Create; SourceBitmap.LoadFromFile(Path+'image'+inttostr(z1)+'.bmp'); Cut.Left := Links; Cut.Top := Oben; Cut.Right := Rechts; Cut.Bottom := Unten;
TargetBitmap.Width := Cut.Right - Cut.Left; TargetBitmap.Height := Cut.Bottom - Cut.Top; Sleep(50); Application.ProcessMessages; BitBlt(TargetBitmap.Canvas.Handle, 0, 0, Cut.Right, Cut.Bottom, SourceBitmap.Canvas.Handle, Cut.Left, Cut.Top, SRCCOPY); TargetBitmap.SaveToFile(Path+'image'+inttostr(z2)+'.bmp'); finally SourceBitmap.Free; TargetBitmap.Free; end;
end; |
Also was macht es für ein Unterschied, das try-finally.
Danke und Lg
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 09.10.10 12:16
Wenn zwischen dem Erzeugen und der Freigabe eine Exception auftritt, werden die Objekte sonst nicht freigegeben.
Der finally-Block wird aber immer ausgeführt, egal ob eine Exception aufgetreten ist oder du mit Exit aus der Prozedur springst. Deshalb wird dann immer freigegeben.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Sa 09.10.10 12:20
Nehmen wir mal folgendes Beispiel:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| src := TBitmap.Create; Src.width := IntToStr(Edit1.Text); Src.Height := IntToStr(Edit2.Text); Src.Free; Src := nil; |
Bist Du Dir GANZ sicher, dass Src IMMER freigegeben wird? Mach Dir den Spaß und teste das mal mit FastMM4 im Hintergrund.
Zum Vergleich nimm mal folgenden Source:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| src := TBitmap.Create; try Src.width := IntToStr(Edit1.Text); Src.Height := IntToStr(Edit2.Text); finally Src.Free; Src := nil; end; |
Den Unterschied siehst Du bei diesen beiden Code-Schnipseln unter Normalbedingungen nicht. Aber geb mal abc in Edit1 ein. Dann dürfte es offensichtlich werden. Finally erzwingt, dass der Code auch im Fehlerfalle ausgeführt wird. Ohne den Schutzblock greift sofort der Exception-Handler und der überspringt halt die Objekt-Freigabe, weil die nicht zur Fehlerbehandlung notwendig ist.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Für diesen Beitrag haben gedankt: HenryHux
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Sa 09.10.10 12:24
Achso, ist ja dann doch praktischer als vermutet
Denke bau ich dann mal besser ein, kann ja denke nicht schaden.
Danke =)
|
|
|