AGB  ·  Datenschutz  ·  Impressum  







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

Speicherleaks TMemoryStream in einem Objekt

Ein Thema von Ykcim · begonnen am 22. Dez 2023 · letzter Beitrag vom 31. Jan 2024
Antwort Antwort
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.164 Beiträge
 
Delphi 10.3 Rio
 
#1

AW: Speicherleaks TMemoryStream in einem Objekt

  Alt 2. Jan 2024, 10:24
Hallo Zusammen,


Delphi-Quellcode:
function TDBService.Get_ProduktReport_General (Kunde: string; Von, Bis: TDate): TStream;
var MxSQL: TMxSQL;
      LStream: TMemoryStream;
begin
   MxSQL := TMxSQL.Create(false);
   LStream := TMemoryStream.Create;
   Try
      LStream := MxSQL.GetF_Report_Produkte_General(Kunde, Von, Bis);
      Logic_Main.FehlerProzedure := 'Get_ProduktReport_General 2';
      Result:= LStream;
   Finally
      MxSQL.Free;
   End;
end;
Hier wird ein Stream erstellt, der aber nicht übergeben wird...
Der erzeugte LStream ist schon ein leak, da die Referenz überschrieben wird un somit nie wieder frei gegeben wird.

Wenn Du im Constructor eine bedingte Erzeugung von Objekten hast, solltest Du im Else-Fall die lokale Instance mit NIL belegen, da Objekte nicht managed sind und daher auch nicht mit NIL initialisiert werden. Ein .free kann dann ggf. crashes da eine zufällige Adresse in der instance steht.

Wenn Du viel mit Streams “spielst” solltest Du Dir einen IStream wrapper schreiben.

Mavarik

PS: Zu Deinem handgeklöppeltem SQL-String sag ich jetzt mal nix - obwohl das sicherlich auch zu Problemen führen kann. Hier solltest Du Dir mal die Verwendung vom Params ansehen.
  Mit Zitat antworten Zitat
Ykcim

Registriert seit: 29. Dez 2006
Ort: NRW
856 Beiträge
 
Delphi 12 Athens
 
#2

AW: Speicherleaks TMemoryStream in einem Objekt

  Alt 16. Jan 2024, 20:48
Hallo Zusammen,

die letzten zwei Wochen bin ich nicht dazu gekommen, an dem Thema weiter zu arbeiten. Habe während meines Urlaubs verschiedene Dinge umgebaut, aber bekomme die Speicherprobleme nicht in den Griff. Habe mich entschieden, die Software noch mal neu aufzubauen und Schritt für Schritt die Speicheraktivitäten zu überprüfen. Ich habe zu viele Proceduren mit der falschen Implementierung erstellt (siehe Anmerkung Delphi.Narium). Außerdem wird die Software wesentlich umfangreicher eingesetzt, als damals gedacht, sodass es jetzt Sinn macht, einige Strukturen neu zu definieren... Das wird aber ein paar Wochen dauern, weil ich das nur abends machen kann...

Eure Hinweise, Erklärungen und Anregungen werden ich dabei versuchen mit einfließen zu lassen.

Dazu hätte ich noch zwei Fragen:
@himitsu:
Was ist ein iStream Wrapper?
Und warum "gefällt" Dir mein SQL-Statement nicht - heißt: warum ist es technisch nicht gut erstellt? Ich mache das nämlich immer so...

Vielen Dank
Patrick
Patrick
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.542 Beiträge
 
Delphi 12 Athens
 
#3

AW: Speicherleaks TMemoryStream in einem Objekt

  Alt 17. Jan 2024, 03:05
QuotedStr ist nicht für SQL (ja, ich weiß, dass es alle verwenden.
QuotedStr ist für die Syntax der Delphi-Strings, im Quellcode und kennt auch nur dessen Escaping.

Für die Datenbanken sollten/müssten Query-Komponenten eigentlich eine passende Funktion irgendwo besitzen, welche die Syntax des jeweiligen SQL-Textes versteht.

Also erstmal vermute ich nicht, dass er etwas "Neues" meint, was jetzt endlich geht.
MultiLine-Strings

Ob Clear und Add oder nur "ein" Text:= ist Geschmackssache.
PS: 'SELECT format(bstlyn__.vrz__dat, ''dd.MM.yyyy'' AS Lieferdatum, '+
Und seit Delphi 12 geht nun sowas:
Code:
      MsQuery.SQL.Add('''
        SELECT format(bstlyn__.vrz__dat, 'dd.MM.yyyy') AS Lieferdatum,
          bstlyn__.bsbn_kla AS Bestellnummer,
          concat(knp__vnm, ' ', knp__nam) AS Besteller,
          bstlyn__.zynrefkl AS ArtNr,
          bstlyn__.afg_oms1 AS Bezeichnung,
          bstlyn__.l_aantal AS Liefermenge,
          bstlyn__.lbn__ref AS Lieferschein,
          konper__.straat__ AS Strasse,
          konper__.post_ref AS PLZ,
          konper__.postnaam AS Ort,
          konper__.land_ref AS Land
        FROM bstlyn__
        LEFT JOIN konper__ ON konper__.lok__ref = bstlyn__.lok__ref
          AND konper__.knp__ref = bstlyn__.knplkref
        LEFT JOIN bstext__ ON bstext__.lyn__ref = bstlyn__.lyn__ref
        LEFT JOIN wafgfl__ ON wafgfl__.lyn__ref = bstlyn__.lyn__ref
        WHERE l_aantal > 0
          AND bstlyn__.kla__ref = :KundenNr
          AND bstlyn__.afg__ref not IN (&VArtikel)
          AND vrz__dat >= :Von
          AND vrz__dat <= :Bis
        ''');
      MsQuery.ParamByName('Von').AsDate := Von;
      MsQuery.ParamByName('Bis').AsDate := Bis;
      MsQuery.ParamByName('KundenNr').AsString := Kunde;
      MsQuery.MacroByName('VArtikel').Value := VArtikel;
(nicht als [DELPHI], da das Forum mit sowas noch Probleme hat und alle führenden Leerzeichen vergisst)


Vermutlich will er aber mehr darauf hinaus, dass es auch andere Möglichkeiten gibt, als "statische" SQLs im Code zu verwenden.
* einmal kann man SQLs auch in andere Dateien (Ressourcen) auslagern, wo es (früher) bessere Möglichkeiten des Schreibens gibt
* oder garkeine Texte, sondern etwas objektorientiertes Selbstgenerierendes
* oder ...
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (17. Jan 2024 um 03:09 Uhr)
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
2.056 Beiträge
 
Delphi 12 Athens
 
#4

AW: Speicherleaks TMemoryStream in einem Objekt

  Alt 17. Jan 2024, 08:39
Was ist ein iStream Wrapper?
Interface-Typen können sich selbst freigeben.
Deswegen denke ich das sowas dir helfen könnte...

Delphi-Quellcode:
type

IMemoryStream = interface
  Function GetStream:TMemoryStream;
  procedure SetStream(aValue:TMemoryStream);
end;
TStreamWrapper=Class(TInterfacedObject, IMemoryStream )
private
  fStream:TMemoryStream
Public
  Function GetStream:TMemoryStream;
  procedure SetStream(aValue:TMemoryStream);
  // Hier könnte man noch alle Stream Methoden hinpaken die man selbst oft benutzt
  // die wrappen quasi die methoden vom TMemoyStream, weil sie einfach nur die selbe Methode in FStream aufrufen.
  Constructor Create;Virtual;
  Destructor Destroy;Override;
  Property Stream:TMemoryStream read GetStream write SetStream;
end;
Implementation


Function TStreamWrapper.SetStream(aValue:TMemoryStream);
Begin
  if Assigned(fStream) then
    FreeAndNil(fStream);// ODER Raise Exception.create('Fehler der Wrapper besitzt bereits einen Stream!');
  fStream := aValue;
end;

Function TStreamWrapper.GetStream:TMemoryStream;
Begin
  Result := fStream
end;

Constructor TStreamWrapper.Create;
Begin
  inherited;
  fStream := nil;
end;

Destructor TStreamWrapper.Destroy;
Begin
  if Assigned(fStream) then
    FreeAndNil(fStream);
  inherited;
end;
Statt Streams als Rückgabewert von Funktionen solltest du den Wrapper ausgeben.
Der Wrapper würde den Stream Freigeben wenn keine Variable mehr den Wrapper referenziert. Daher kommt es nicht mehr zu Speicherlecks wenn du den Stream nicht freigibst.
Mann nennt das ARC...RC steht für Referenzählung...
Wichtig ist das NUR der Wrapper den Stream kennt. Sonnst kommt es zwar nicht so Speicherlecks aber zu "use after free" Fehlern.

Man benutzt es so dass man nur IMemorystream referenziert!
Delphi-Quellcode:
var LStream:IMemoryStream := (TStreamWrapper.create as IMemoryStream );
LStream.Stream := TMemoryStream.create;
Andreas
Nobody goes there anymore. It's too crowded!

Geändert von QuickAndDirty (17. Jan 2024 um 08:59 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.542 Beiträge
 
Delphi 12 Athens
 
#5

AW: Speicherleaks TMemoryStream in einem Objekt

  Alt 17. Jan 2024, 08:46
Leider ist von Microsoft das IStream nicht kompatibel mit Delphis TStream (von den Methoden her)
und für die Verwendung braucht man ja immernoch das Delphi-Objekt.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
2.056 Beiträge
 
Delphi 12 Athens
 
#6

AW: Speicherleaks TMemoryStream in einem Objekt

  Alt 17. Jan 2024, 09:02
Leider ist von Microsoft das IStream nicht kompatibel mit Delphis TStream (von den Methoden her)
und für die Verwendung braucht man ja immernoch das Delphi-Objekt.
Warum wurde TStream nicht gleich als Interface umgesetzt?
Andreas
Nobody goes there anymore. It's too crowded!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.542 Beiträge
 
Delphi 12 Athens
 
#7

AW: Speicherleaks TMemoryStream in einem Objekt

  Alt 17. Jan 2024, 09:37
Weil Pascal/Delphi "objektorientiert" ist
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
2.056 Beiträge
 
Delphi 12 Athens
 
#8

AW: Speicherleaks TMemoryStream in einem Objekt

  Alt 17. Jan 2024, 10:07
Ich dachte interfaces/traits/behaviors gehören zum OO Baukasten dazu.
Andreas
Nobody goes there anymore. It's too crowded!
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
10.054 Beiträge
 
Delphi 12 Athens
 
#9

AW: Speicherleaks TMemoryStream in einem Objekt

  Alt 17. Jan 2024, 12:08
Weil Pascal/Delphi "objektorientiert" ist
Hinter einer Interfacereferenz steckt eine referenzgezählte Objektinstanz.

Warum wurde TStream nicht gleich als Interface umgesetzt?
Das wäre sicherlich an einigen Stellen wünschenswert (TList, TDictionary, TStream, TDataset, ...), aber wenn dann jemand diese Klassen als Objektreferenzen einsetzt und irgendwo aus Versehen als Interface übergibt, wäre das doof. Insofern ist es schon auch schwierig, wenn solche Klassen auch als Interface angeboten würden. Und nur als Interface wäre wieder u.a. ein Performancethema und nachträglich kaum machbar.
Sebastian Jänicke
AppCentral
  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 19:36 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz