Autor Beitrag
HenryHux
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1054
Erhaltene Danke: 78

Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: Fr 08.10.10 12:09 
Ok, und wie werden die Bilder aus dem RAM gelöscht?
Mit imagex.free?
platzwart
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1054
Erhaltene Danke: 78

Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: Fr 08.10.10 12:18 
Ok, also die Bitmaps werden zuerst geshootet, dann geschnitten und anschließend verglichen.
Dazu folgende Funktionen:
ausblenden 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;


ausblenden 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, 00, Cut.Right, Cut.Bottom, SourceBitmap.Canvas.Handle, Cut.Left, Cut.Top, SRCCOPY);
  SourceBitmap.Canvas.Refresh;
  TargetBitmap.SaveToFile(Path+'image'+inttostr(z2)+'.bmp');
end;


ausblenden 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:
ausblenden 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:
ausblenden 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



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1054
Erhaltene Danke: 78

Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
BeitragVerfasst: Fr 08.10.10 12:24 
ausblenden 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



BeitragVerfasst: Fr 08.10.10 12:32 
Und ein Ressourcenschutzblock könnte auch nicht schaden. Und was soll das:
ausblenden Delphi-Quelltext
1:
2:
Sleep(50);
Application.ProcessMessages;
HenryHux Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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:
ausblenden 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>0and (bitmap2>0and (bitmap3>0and (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:
user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
Und ein Ressourcenschutzblock könnte auch nicht schaden. Und was soll das:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 09.10.10 11:27 
user profile iconHenryHux hat folgendes geschrieben Zum zitierten Posting springen:
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:


ausblenden 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 ;-)

user profile iconHenryHux hat folgendes geschrieben Zum zitierten Posting springen:
Wenn es daran liegt, dass ich FastMM4 nicht als erste Unit habe, wie könnte ich das denn dann machen?

Lg

Ich wiederhole mal:
user profile iconFlamefire hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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:
ausblenden 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.
ausblenden Delphi-Quelltext
1:
2:
  FullDebugModeScanMemoryPoolBeforeEveryOperation: Boolean = true;
  FullDebugModeRegisterAllAllocsAsExpectedMemoryLeak: Boolean = true;


Kann man in den Informationen schon iwas erkennen?

Lg
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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 :D
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?
ausblenden 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, 00, Cut.Right, Cut.Bottom, SourceBitmap.Canvas.Handle, Cut.Left, Cut.Top, SRCCOPY);
  //  SourceBitmap.Canvas.Refresh;
    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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 09.10.10 12:20 
Nehmen wir mal folgendes Beispiel:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
src := TBitmap.Create;
Src.width := IntToStr(Edit1.Text);
Src.Height := IntToStr(Edit2.Text);
//Some more obscure source
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:
ausblenden 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);
    //Some more obscure source
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: Sa 09.10.10 12:24 
Achso, ist ja dann doch praktischer als vermutet :D
Denke bau ich dann mal besser ein, kann ja denke nicht schaden.
Danke =)