AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Memory Leak nach Zuweisung eines Resourcestream
Thema durchsuchen
Ansicht
Themen-Optionen

Memory Leak nach Zuweisung eines Resourcestream

Ein Thema von Peter-Pascal · begonnen am 4. Jun 2022 · letzter Beitrag vom 14. Jun 2022
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von himitsu
himitsu

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

AW: Memory Leak nach Zuweisung eines Resourcestream

  Alt 4. Jun 2022, 14:11
Ob in die EXE oder in eine DLL macht technisch keinen Unterschied. Man braucht nur das Handle des entsprechenden Moduls.
in Delphi ist HInstance das Handle der EXE/DLL, wo der Code drin ist. (aufpassen, wenn mit Packages compiliert)


Hier im Forum suchensvg / Bei Google suchendelphi svg
https://en.delphipraxis.net/topic/33...ort-in-delphi/
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Peter-Pascal

Registriert seit: 18. Feb 2007
Ort: 32139 Spenge
197 Beiträge
 
Delphi 11 Alexandria
 
#12

AW: Memory Leak nach Zuweisung eines Resourcestream

  Alt 4. Jun 2022, 22:31
noch mal vielen Dank,
der Link zum SVG ist sehr wertvoll
Peter Niemeier
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

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

AW: Memory Leak nach Zuweisung eines Resourcestream

  Alt 7. Jun 2022, 17:53
Also ich mache das schon immer so...

Ich packe alle Resourcen per zlib und binde diese ein...

Ob in einer DLL oder in der Exe ist fast egal, es sei den, Du brauchst die Speicherkachel von ~2GB (3GB mit flag) voll und ganz für die exe...

Mavarik
  Mit Zitat antworten Zitat
Rolf Frei

Registriert seit: 19. Jun 2006
647 Beiträge
 
Delphi 11 Alexandria
 
#14

AW: Memory Leak nach Zuweisung eines Resourcestream

  Alt 7. Jun 2022, 18:13
Also eine Resourcen DLL ist so ziemlich das Dümmste was du machen kannst. Ausser dass du deutlich mehr Aufwand hast (2 Projektet die jeweils kompiliert werden, 2 Dateien die ausgeleifert werden müssen, etc.) bringt das überhaupt keine Voreteile. Du kannst die Bilder problemlos in deine EXE linken. Die Resoucen werden erst geladen, wenn du sie explizit lädst. Also mit Resourcensparen hat das nichts zu tun.
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

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

AW: Memory Leak nach Zuweisung eines Resourcestream

  Alt 8. Jun 2022, 03:07
Die Resoucen werden erst geladen, wenn du sie explizit lädst. Also mit Resourcensparen hat das nichts zu tun.
Das ist natürlich nicht so...
Die Resourcen sind immer da...
Vielleicht verwechselst Du das mit den Resourcen die dann oben drauf nochmal für die Bilder benötigt werden...
Natürlich macht es Sinn Resourcen in eine DLL auszulagern...

1.) DLL Laden
2.) Resourcen extrahieren
3.) DLL wieder aus dem Speicher werfen...

Somit bleibt fürs Hauptprogramm wieder der volle Speichern.
  Mit Zitat antworten Zitat
Peter-Pascal

Registriert seit: 18. Feb 2007
Ort: 32139 Spenge
197 Beiträge
 
Delphi 11 Alexandria
 
#16

AW: Memory Leak nach Zuweisung eines Resourcestream

  Alt 8. Jun 2022, 13:03
Hallo Mavarik,

habe ich Dich richtig verstanden, Du bindest alle Bilder (png, jepeg ua) in eine Zip-Datei und holst sie dann bei Bedarf aus der Datei?

Das ist vermutlich hinsichtlich benötigten Speicherplatzes auf der HDU die beste Variante.

Gruß Peter
Peter Niemeier
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Memory Leak nach Zuweisung eines Resourcestream

  Alt 8. Jun 2022, 13:08
@Mavarik / Rolf Frei:

Jupp, länger "ungenutzter" Speicher kann von Windows aus dem RAM (ühysischer Speicher) geworfen werden,
aber im virtuellen Programmspeicher bleibt es dennoch vorhanden und belegt ihn (bei 32-Bit sind die normalen 2GB schnell voll)
Resourcen-DLL wieder entladen, macht auch da den Platz wieder frei.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
472 Beiträge
 
#18

AW: Memory Leak nach Zuweisung eines Resourcestream

  Alt 8. Jun 2022, 19:11
habe ich Dich richtig verstanden, Du bindest alle Bilder (png, jepeg ua) in eine Zip-Datei und holst sie dann bei Bedarf aus der Datei?
Als Beispiel habe ich dir eine Umsetzung mit mORMot geschrieben.

Disclaimer: Das Beispiel ist ein Proof of Concept, der Sourcecode ist weder getestet noch optimiert.
Delphi-Quellcode:
uses
  mormot.core.base,
  mormot.core.data,
  mormot.core.text,
  mormot.core.os,
  mormot.core.zip,
  mormot.core.perf,
  mormot.crypt.core;

type
  TImageResourceFile = class(TObject)
  private
    FPassword: RawUtf8;
    FFileName: TFileName;
    FIsWritable: Boolean;
  protected
    function LoadStream(pmStream: TCustomMemoryStream; const pmcResName: TFileName; const pmcPassword: RawUtf8): Boolean;
    procedure SaveStream(pmStream: TCustomMemoryStream; const pmcResName: TFileName; const pmcPassword: RawUtf8; pmIsCompressed: Boolean = True);
  public
    constructor Create(const pmcFileName: TFileName; const pmcPassword: RawUtf8);
    destructor Destroy; override;
    function LoadImage(pmImage: TImage; const pmcImageName: String): Boolean;
    procedure SaveImage(pmImage: TImage; const pmcImageName: String); overload;
    procedure SaveImage(pmImageData: TCustomMemoryStream; const pmcImageName: String); overload;
  end;

constructor TImageResourceFile.Create(const pmcFileName: TFileName; const pmcPassword: RawUtf8);
begin
  inherited Create;
  FFileName := pmcFileName;
  FPassword := pmcPassword;
  FIsWritable := IsDirectoryWritable(ExtractFilePath(FFileName));
end;

destructor TImageResourceFile.Destroy;
begin
  FillZero(FPassword);
  inherited Destroy;
end;

function TImageResourceFile.LoadStream(pmStream: TCustomMemoryStream; const pmcResName: TFileName; const pmcPassword: RawUtf8): Boolean;
var
  idx: Integer;
  zipRead: TZipRead;
  encStream: TMemoryStream;
  aesReader: TAesPkcs7Reader;
begin
  Result := False;
  if pmStream = Nil then Exit; //=>
  if pmcResName = 'then Exit; //=>
  if not FileExists(FFileName) then Exit; //=>

  zipRead := TZipRead.Create(FFileName);
  try
    idx := zipRead.NameToIndex(pmcResName);
    if idx < 0 then Exit; //=>

    if pmcPassword = 'then
      Result := zipRead.UnZip(idx, pmStream)
    else
    begin
      encStream := TMemoryStream.Create;
      try
        if zipRead.UnZip(idx, encStream) then
        begin
          encStream.Position := 0;
          aesReader := TAesPkcs7Reader.Create(encStream, pmcPassword);
          try
            Result := (StreamCopyUntilEnd(aesReader, pmStream) > 0);
          finally
            aesReader.Free;
          end;
        end;
      finally
        encStream.Free;
      end;
    end;
  finally
    zipRead.Free;
  end;
end;

procedure TImageResourceFile.SaveStream(pmStream: TCustomMemoryStream; const pmcResName: TFileName; const pmcPassword: RawUtf8; pmIsCompressed: Boolean);
const
  IS_COMPRESSED: array[Boolean] of Integer = (0, 6);
var
  zipWrite: TZipWrite;
  encStream: TMemoryStream;
  aesWriter: TAesPkcs7Writer;
begin
  if pmStream = Nil then Exit; //=>
  if pmcResName = 'then Exit; //=>
  if not FIsWritable then Exit; //=>

  if FileExists(FFileName) then
    zipWrite := TZipWrite.CreateFromIgnore(FFileName, [pmcResName])
  else
    zipWrite := TZipWrite.Create(FFileName);

  try
    if pmcPassword = 'then
      zipWrite.AddDeflated(pmcResName, pmStream.Memory, pmStream.Size, IS_COMPRESSED[pmIsCompressed], DateTimeToFileDate(Now))
    else
    begin
      encStream := TMemoryStream.Create;
      try
        aesWriter := TAesPkcs7Writer.Create(encStream, pmcPassword);
        try
          pmStream.Position := 0;
          StreamCopyUntilEnd(pmStream, aesWriter);
          aesWriter.Finish;
        finally
          aesWriter.Free;
        end;

        zipWrite.AddDeflated(pmcResName, encStream.Memory, encStream.Position, IS_COMPRESSED[pmIsCompressed], DateTimeToFileDate(Now));
      finally
        encStream.Free;
      end;
    end;
  finally
    zipWrite.Free;
  end;
end;

function TImageResourceFile.LoadImage(pmImage: TImage; const pmcImageName: String): Boolean;
var
  tmpStream: TMemoryStream;
begin
  Result := False;
  if pmImage = Nil then Exit; //=>
  if pmcImageName = 'then Exit; //=>

  tmpStream := TMemoryStream.Create;
  try
    if LoadStream(tmpStream, pmcImageName, FPassword) then
    begin
      tmpStream.Position := 0;
      try
        pmImage.Picture.LoadFromStream(tmpStream);
        Result := True;
      except
      end;
    end;
  finally
    tmpStream.Free;
  end;
end;

procedure TImageResourceFile.SaveImage(pmImage: TImage; const pmcImageName: String);
var
  tmpStream: TMemoryStream;
begin
  if pmImage = Nil then Exit; //=>
  if pmcImageName = 'then Exit; //=>

  tmpStream := TMemoryStream.Create;
  try
    pmImage.Picture.SaveToStream(tmpStream);
    SaveImage(tmpStream, pmcImageName);
  finally
    tmpStream.Free;
  end;
end;

procedure TImageResourceFile.SaveImage(pmImageData: TCustomMemoryStream; const pmcImageName: String);
begin
  if pmImageData = Nil then Exit; //=>
  if pmcImageName = 'then Exit; //=>

  SaveStream(pmImageData, pmcImageName, FPassword, False);
end;
Anwenden kannst du es so:
Delphi-Quellcode:
var
  timer: TPrecisionTimer;
  imgResFile: TImageResourceFile;
begin
  Image.Picture.Assign(Nil);

  timer.Start;
  imgResFile := TImageResourceFile.Create(ChangeFileExt(Application.ExeName, '.dat'), 'Thomas');
  try
    imgResFile.LoadImage(Image, 'ImageName');
    ShowMessage(Format('Total time: %s', [timer.Stop]));
  finally
    imgResFile.Free;
  end;
end;
Eine 2MB große AES verschlüsselte PNG Bilddatei aus einer Zip-Datei in ein Image laden, benötigt im Beispiele eine Gesamtladezeit von ca. 60 ms. Das ist ein brauchbarer Wert. Davon dauert die Entschlüsselung ca. 5 ms. Wenn du viele Bilder auf einmal schreiben willst, solltest du dir eine BatchAdd Funktion schreiben.

mORMot musst du nicht installierten. Es reicht aus, die entsprechenden Bibliothekspfade einzufügen. Es steht eine ausführliche Hilfe, viele Beispiele (für mORMot1) und ein freundliches Forum zur Verfügung.
Bei einer neuen Anwendung würde ich mORMot2 empfehlen. Dazu gibt es zur Zeit noch keine Hilfe. Trotzdem hier der Link zum GitHub Repro.

Bis bald...
Thomas

Geändert von mytbo ( 8. Jun 2022 um 20:09 Uhr) Grund: Ups, Funktionsergebnis vergessen!
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
472 Beiträge
 
#19

AW: Memory Leak nach Zuweisung eines Resourcestream

  Alt 14. Jun 2022, 12:04
Interessanter Nachtrag: Wenn man anstelle der Vcl.Imaging.pngimage besser die mormot.ui.gdiplus Unit verwendet, verkürzt sich das Speichern eines 2MB großen PNG-Bildes mit SaveImage() auf 9 ms gegenüber 900 ms mit der Delphi Unit und ein LoadImage() wird in 10 ms anstatt 80 ms ausgeführt. Es lohnt sich, habe auch nichts anderes erwartet.

Bis bald...
Thomas

Geändert von mytbo (14. Jun 2022 um 12:18 Uhr) Grund: Zeitwert korrigiert
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


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 14:39 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