AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

EOutOfResource + Thread + Bitmap + Assign

Ein Thema von silver-moon-2000 · begonnen am 3. Mär 2013 · letzter Beitrag vom 3. Mär 2013
Antwort Antwort
silver-moon-2000

Registriert seit: 18. Feb 2007
Ort: Schweinfurt
170 Beiträge
 
Delphi XE Professional
 
#1

EOutOfResource + Thread + Bitmap + Assign

  Alt 3. Mär 2013, 12:30
Delphi-Version: XE
Hallo,

ich wende mich wieder mal mit einem Fehler an Euch, auf dessen Schliche ich nicht komme...

Ich habe einen Thread, der einen "Bild" auf ein Bitmap zeichnen soll.
Dieses Bitmap soll dann in der GUI in einem Image angezeigt werden

Delphi-Quellcode:
type TDisplayHandler = class(TThread)
[...]

constructor TDisplayHandler.Create(_createSuspended : Boolean);
begin
  FBitmap := TBitmap.Create;
[...]
end;


destructor TDisplayHandler.Destroy;
begin
  FreeAndNil(FBitmap);
[...]
end;


procedure TDisplayHandler.DisplayBitmap(_data : TObjectList<TTorqueData>);
//-> wird von einem Timer regelmäßig aufgerufen
begin
  FData := _Data;
  if FIsDone then //Graph wurde fertig berechnet, neuer kann berechnet werden
    FIsDone := False;
end;


procedure TDisplayHandler.SyncEvent;
begin
// if Assigned(FBitmapChangeEvent) then
// FBitmapChangeEvent(FBitmap);
//eigentlich so, aber dahinter steht effektiv auch nur ein:
  frmMain.Image.Picture.Assign(FBitmap);
end;

procedure TDisplayHandler.Execute;
begin
  while not Terminated do
  begin
    if not FIsDone then
    begin
      DoCreate;
      Synchronize(SyncEvent);
      FIsDone := True;
    end
    else
      Sleep(20);
  end;
end;

end.
Nach einiger Zeit, jedoch unterschiedlich, mal 10 mal 100 Timeraufrufe später, bricht er ab mit
Code:
Project Torque.exe raised exception class EOutOfResources with message 'Out of system resources'.
Der Cursor hängt dann in der Methode DoCreate und zwar dort an der ersten Stelle, an der ich auf das Bitmap zugreifen will

Delphi-Quellcode:
procedure TDisplayTorqueOverTime.DoCreate;
begin
[...]
  clearBitmap(FBitmap);
  drawLine(0, FXAxisPos, FWidth, FXAxisPos, clBlack, 3, FBitmap.Canvas); //hier hängt der Cursor
  drawLine(FYAxisPos, 0, FYAxisPos, FHeight, clBlack, 3, FBitmap.Canvas);

[...]

//mit

procedure clearBitmap(_bitmap : TBitmap);
//-> überzeichnet das Canvas des angegebenen Bitmaps weiß
var t_brush : TBrush;
begin
  if Assigned(_bitmap) then
  begin
    t_brush := Tbrush.Create;
    t_brush.Assign(_bitmap.Canvas.Brush);
    _bitmap.Canvas.Brush.Color := clWhite;
    _bitmap.Canvas.Brush.Style := bsSolid;
    _bitmap.Canvas.FillRect(Rect(0, 0, _bitmap.Width, _bitmap.Height));
    _bitmap.Canvas.Brush.Assign(t_brush);
    t_brush.Free;
  end;
end;

procedure drawLine(_x1, _y1, _x2, _y2 : Integer; _color : TColor; _width : Integer; _canvas : TCanvas);
//-> zeichnet im angegebenen Canvas eine Linie
//-> Pen wird dabei nicht verändert, da er zwischengespeichert wird
var t_pen : TPen;
begin
  if Assigned(_canvas) then
  begin
    t_pen := TPen.Create;
    t_pen.Assign(_canvas.Pen);
    _canvas.Pen.Color := _color;
    _canvas.Pen.Width := _width;
    _canvas.MoveTo(_x1, _y1);
    _canvas.LineTo(_x2, _y2);
    _canvas.Pen.Assign(t_pen);
    t_pen.Free;
  end;
end;
Ich finde meinen Fehler nicht, denn FBitmap wird ja nur einmal erstellt undd er Zugriff auf die GUI wird synchronisiert. Oder mache ich einen kapitalen Denkfehler (wäre nicht das erste Mal)?

Für Hilfe wäre ich wie immer immens dankbar...
Tobias
Bitte nicht hauen , ich weiß es nicht besser

Geändert von silver-moon-2000 ( 3. Mär 2013 um 12:31 Uhr) Grund: falsche Delphi Version angegeben
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#2

AW: EOutOfResource + Thread + Bitmap + Assign

  Alt 3. Mär 2013, 13:25
Ich würd zunächst in die DPR an den Anfang ReportMemoryLeaksOnShutdown := True schreiben und dann mal die Anwendung mal manuell beenden, bevor die Exception kommt. Dann siehst du (wahrscheinlich) zumindest schon mal, was da eigentlich den Speicher zumüllt. Wo der Cursor stehen bleibt, ist nämlich wenig aussagekräftig, denn das zeigt dir ja nur, wo der Tropfen das Fass zum Überlaufen gebracht hat.

Ansonsten seh ich da jetzt auf den ersten Blick nichts. Ich denke, da ist mehr Code erforderlich, um eine Diagnose zu stellen... z.B. seh ich nirgendwo den Timer, von dem du redest.

Was noch sein könnte, ist, dass innerhalb des Threads eine stille Exception auftritt, wodurch eine Routine frühzeitig abgebrochen wird, bevor ein Objekt freigegeben wird. In solchen Fällen ist Try-Finally wirklich wichtig. Du kannst ja mal einen Breakpoint in den Thread setzen um dir die Exceptions anzeigen zu lassen.
  Mit Zitat antworten Zitat
silver-moon-2000

Registriert seit: 18. Feb 2007
Ort: Schweinfurt
170 Beiträge
 
Delphi XE Professional
 
#3

AW: EOutOfResource + Thread + Bitmap + Assign

  Alt 3. Mär 2013, 14:36
Danke für Deine Antwort,

Wenn ich ReportMemoryLeaksOnShutdown := True verwende, poppt kein Fenster auf, das mich darüber informiert, wie schlecht ich programmiere, also gehe ich davon aus, zumindest keine allzu offensichtlichen Speicherlöcher zu hinterlassen

Seltsam, sobald ich die Synchronize-Methode auskommentiere, läuft das Programm "stundenlang" fehlerfrei:
Delphi-Quellcode:
procedure TDisplayHandler.Execute;
begin
  while not Terminated do
  begin
    if not FIsDone then
    begin
      DoCreate;
     // Synchronize(SyncEvent); //wenn das auskommentiert ist, läuft das Programm
      FIsDone := True;
    end
    else
      Sleep(20);
  end;
end;
Mit anderen Worten: Das Bitmap wird nach wie vor "bemalt", jedoch nicht mehr per Assign in das Image der MainForm "kopiert",
das schließt mMn einen Fehler bei der "Speicherzumüllung" aus.
Also muss mMn ein Fehler bei der Übergabe an die GUI passieren, obwohl der Zugriff darauf synchronized ist?
Tobias
Bitte nicht hauen , ich weiß es nicht besser
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#4

AW: EOutOfResource + Thread + Bitmap + Assign

  Alt 3. Mär 2013, 14:45
Ah halt, er sagt ja auch „System Resources“ und nicht „Memory“.

Da fällt mir ein, ich hatte glaube ich vor gar nicht all zu langer Zeit ein ähnliches Problem – ich bin mir nicht mehr 100%ig sicher, aber ich glaube es war so, dass GDI-Objekte immer einem bestimmten Thread angehören. D.h. du kannst sie nicht im einen Thread erzeugen und in einem anderen verwenden, bzw. es kann dann zu Fehlern kommen. Genau das tust du aber, weil der contructor des Threads noch im Hauptthread ausgeführt wird.

Schieb die Erzeugung von FBitmap mal vom constructor in die Execute-Methode (und die Freigabe natürlich auch).


Gerade im fraglichen Projekt, wo der Fehler bei mir auftrat, noch mal nachgeschaut. Vergiss das mit dem constructor. Du musst einfach nur Canvas.Lock/Unlock vor und nach deinen Zeichenoperationen aufrufen. Das war des Rätsels Lösung.

Edit²: Hat zumindest bei mir gereicht.

Geändert von Namenloser ( 3. Mär 2013 um 15:01 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
17.195 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: EOutOfResource + Thread + Bitmap + Assign

  Alt 3. Mär 2013, 14:50
... aber ich glaube es war so, dass GDI-Objekte immer einem bestimmten Thread angehören. ...
Genau das ist es. Windows-GDI-Ressourcen sind Thread-Affine. D.h. auf sie darf nur im erzeugenden Thread zugegriffen werden. Ansonsten kracht irgendwo irgendwas.
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
silver-moon-2000

Registriert seit: 18. Feb 2007
Ort: Schweinfurt
170 Beiträge
 
Delphi XE Professional
 
#6

AW: EOutOfResource + Thread + Bitmap + Assign

  Alt 3. Mär 2013, 15:18
Gerade im fraglichen Projekt, wo der Fehler bei mir auftrat, noch mal nachgeschaut. Vergiss das mit dem constructor. Du musst einfach nur Canvas.Lock/Unlock vor und nach deinen Zeichenoperationen aufrufen. Das war des Rätsels Lösung.

Edit²: Hat zumindest bei mir gereicht.
Anscheinend nicht nur bei Dir...
Seltsam, seltsam...

... aber ich glaube es war so, dass GDI-Objekte immer einem bestimmten Thread angehören. ...
Genau das ist es. Windows-GDI-Ressourcen sind Thread-Affine. D.h. auf sie darf nur im erzeugenden Thread zugegriffen werden. Ansonsten kracht irgendwo irgendwas.
OK, wieder was gelernt.

Auf jeden Fall vielen Dank für Eure Antworten,
andere Baustellen rufen mich jedoch , da jetzt diese anscheinend begradigt wurde
Tobias
Bitte nicht hauen , ich weiß es nicht besser
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:33 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz