AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

String freigeben nur wo?

Ein Thema von EWeiss · begonnen am 18. Feb 2019 · letzter Beitrag vom 27. Feb 2019
Antwort Antwort
Seite 1 von 2  1 2   
EWeiss
(Gast)

n/a Beiträge
 
#1

String freigeben nur wo?

  Alt 18. Feb 2019, 07:59
Mein Problem ist leider immer noch nicht gelöst.

EurekaLog!
Zitat:
--------------------------------------------------------------------------------------------------------------------------------------
|Methods |Details|Stack |Address |Module |Offset |Unit |Class |Procedure/Method |Line |
--------------------------------------------------------------------------------------------------------------------------------------
|+Leak #1: Type=UnicodeString: Ref count - 1, Content: "'WARNING: DO NOT CHANGE THE ORDER OF THE PROPERTIES!"; Total size=118; Count=1|
|------------------------------------------------------------------------------------------------------------------------------------|
|00000002|03 |00000000|005E8586|SK_Aero.dll |00008586|System | |InternalUStrFromPCharLen | |
|00000002|04 |00000000|0082C55B|SK_Aero.dll |0024C55B|uSkinConfig|TSkinConfig|FBuffin |976[12] |
|00000002|04 |00000000|0082ABEF|SK_Aero.dll |0024ABEF|uSkinConfig|TSkinConfig|GetConfiguration |308[5] |
|00000002|04 |00000000|008234C4|SK_Aero.dll |002434C4|uSkin |TSkinEngine|InitSkin |644[25] |
|00000002|04 |00000000|00833E1B|SK_Aero.dll |00253E1B|uMaster | |SKAERO_InitSkin |806[4] |
|00000002|03 |00000000|75213366|kernel32.dll|00013366|kernel32 | |BaseThreadInitThunk | |
|00000002|03 |00000000|77019900|ntdll.dll |00039900|ntdll | | (possible RtlInitializeExceptionChain+97)| |
|00000002|03 |00000000|770198CE|ntdll.dll |000398CE|ntdll | | (possible RtlInitializeExceptionChain+47)| |
|------------------------------------------------------------------------------------------------------------------------------------|
Das Problem liegt hier.
FBuffin

Wenn ich im Dialog von EurekaLog doppelkicke dann geht er mir in diese Zeile.
Delphi-Quellcode:
  try
    try
      while not eof(ParseFile) do
      begin
        ReadLN(ParseFile, sBuffer);
        AppendToLinkedList(nReading, sBuffer); // sBuffer soll einen Memoryleak produzieren.
        inc(nReading);
      end;
    except
      raise Exception.Create(SysErrorMessage(GetLastError));
    end;
  finally
    nReading := 0;
    CloseFile(ParseFile);
  end;
Das Problem ist nur, ich weis nicht wo ich ihn freigeben soll.
Theoretisch würde ich es so machen.
Delphi-Quellcode:
      while not eof(ParseFile) do
      begin
        ReadLN(ParseFile, sBuffer);
        AppendToLinkedList(nReading, sBuffer); // sBuffer soll einen Memoryleak produzieren.
        inc(nReading);
        // String freigeben nachdem er übergeben wurde
        ZeroMemory(Pointer(sBuffer), Length(sBuffer) * SizeOf(Char));
        sBuffer := '';
      end;
Nur dann lösche ich den String im Array dieser ist dann auch '' obwohl ich den String erst nach der Übergabe lösche.
Delphi-Quellcode:
procedure AppendToLinkedList(nReading: Integer; sBuffer: string);
begin

  New(FPBuffer);

  if nReading = 0 then
  Begin
    New(FToPBuffer);
    LineStart := FToPBuffer;
    LineStart^.Nr := 0;
  end;

  FPBuffer^.Nr := nReading;
  FPBuffer^.Str := sBuffer; //<< der ist dann nachdem löschen von sBuffer leer
  LineStart^.Max := FPBuffer^.Nr;
  FToPBuffer^.Ptr := FPBuffer;
  FToPBuffer := FPBuffer;
end;
Keine Ahnung wo ich den String sonst freigeben soll wenn nicht an angezeigter Position.

Edit:
Hier das gleiche!
Delphi-Quellcode:
procedure FormatINI(Filename: string);
var
  sBuffer: string;
  ParseFile: TextFile;
  StringList: TStringList;
  StringParse: string;

procedure AppendToLinkedList(nReading: Integer; sBuffer: string);
begin

  New(FPBuffer);

  if nReading = 0 then
  Begin
    New(FToPBuffer);
    LineStart := FToPBuffer;
    LineStart^.Nr := 0;
  end;

  FPBuffer^.Nr := nReading;
  FPBuffer^.Str := sBuffer;
  LineStart^.Max := FPBuffer^.Nr;
  FToPBuffer^.Ptr := FPBuffer;
  FToPBuffer := FPBuffer;
end;

begin
  StringList := TStringList.Create;

  Assignfile(ParseFile, Filename);
  reset(ParseFile);

  try
    try
      while not eof(ParseFile) do
      begin
        ReadLN(ParseFile, sBuffer);
        AppendToLinkedList(nReading, sBuffer);
        inc(nReading);
      end;
    except
      raise Exception.Create(SysErrorMessage(GetLastError));
    end;
  finally
    nReading := 0;
    CloseFile(ParseFile);
  end;

  FPBuffer := LineStart;
  while (FPBuffer.Nr <= LineStart.Max - 1) do
  begin
    FPBuffer := FPBuffer.Ptr;
    StringParse := LeftTrim(FPBuffer.Str);
    if Length(StringParse) <> 0 then
      StringList.Add(FPBuffer^.Str);

    if FPBuffer.Nr > 0 then
      if LeftStr(FPBuffer^.Str, 1) = '[then
        StringList.Insert(StringList.IndexOf(StringParse), '');

    ZeroMemory(PWideChar(FPBuffer.Str), Length(FPBuffer.Str) * SizeOf(Char));
    FPBuffer.Str := '';
  end;

  StringList.SaveToFile(Filename);
  StringList.Free;

  Dispose(FPBuffer);
  FPBuffer := nil;
  LineStart := nil;

end;
siehe Shot.. Doppelklick auf FormatINI dann springt er in diese Zeile. AppendToLinkedList(nReading, sBuffer);
gruss

Geändert von EWeiss (11. Jul 2019 um 15:55 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
10.989 Beiträge
 
Delphi 12 Athens
 
#2

AW: String freigeben nur wo?

  Alt 18. Feb 2019, 08:35
Das ZeroMemory ist hier wohl eher schädlich, da es die Referenzzählung der Strings umgeht. Ein Finalize(FPBuffer^) sollte da verträglicher sein.

Was mir auffällt ist, daß für jede Zeile im AppendToLinkedList ein New() aufgerufen wird, es aber nur ein einziges Dispose() gibt.

Außerdem vermisse ich die Initialisierung von nReading mit 0.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#3

AW: String freigeben nur wo?

  Alt 18. Feb 2019, 08:42
Das ZeroMemory ist hier wohl eher schädlich, da es die Referenzzählung der Strings umgeht. Ein Finalize(FPBuffer^) sollte da verträglicher sein.

Was mir auffällt ist, daß für jede Zeile im AppendToLinkedList ein New() aufgerufen wird, es aber nur ein einziges Dispose() gibt.
Könntest du mir bitte an Hand meines Codes das korrigieren wenn du zeit dazu findest?

Zitat:
Außerdem vermisse ich die Initialisierung von nReading mit 0.
FPBuffer^.Nr := nReading;

Nun das ist schon gegeben..
nReading ist 0 beim start.
Aber ich kann es noch ändern wobei ich aber denke das es nicht nötig ist.
Wenn ich eine Variable als integer definiere dann ist automatisch wenn nichts anderes angegeben wird der erste wert = 0 oder liege ich da falsch?
In dem Fall muss ich nReading nicht extra 0 zuweisen.

Aber wenn das für dich besser ist? Kein Problem.
Delphi-Quellcode:
  try
    try
      nReading := 0;
      while not eof(ParseFile) do
      begin
        ReadLN(ParseFile, sBuffer);
        AppendToLinkedList(nReading, sBuffer);
        inc(nReading);
      end;
    except
      raise Exception.Create(SysErrorMessage(GetLastError));
    end;
  finally
    CloseFile(ParseFile);
  end;
gruss

Geändert von EWeiss (18. Feb 2019 um 08:58 Uhr)
  Mit Zitat antworten Zitat
DasWolf

Registriert seit: 7. Jun 2016
75 Beiträge
 
Delphi 10.1 Berlin Professional
 
#4

AW: String freigeben nur wo?

  Alt 18. Feb 2019, 09:10
Wenn ich eine Variable als integer definiere dann ist automatisch wenn nichts anderes angegeben wird der erste wert = 0 oder liege ich da falsch?
Falsch.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
10.989 Beiträge
 
Delphi 12 Athens
 
#5

AW: String freigeben nur wo?

  Alt 18. Feb 2019, 09:11
Zitat:
Wenn ich eine Variable als integer definiere dann ist automatisch wenn nichts anderes angegeben wird der erste wert = 0 oder liege ich da falsch?
Das gilt nur bei globalen Variablen und Feldern in Klassen. Lokale Variablen enthalten zufällige Inhalte.

Ich würde es aber in jedem Fall vor der while-Schleife setzen, denn dann könnte man die procedure auch mehrmals aufrufen.


In dem Code habe ich sonst nur das Freigeben der Strings entfernt und eine Schleife zum Freigeben der linked List eingebaut. Vielleicht ist das MemoryLeak damit ja schon behoben.
Delphi-Quellcode:
procedure FormatINI(Filename: string);
var
  sBuffer: string;
  ParseFile: TextFile;
  StringList: TStringList;
  StringParse: string;

procedure AppendToLinkedList(nReading: Integer; sBuffer: string);
begin

  New(FPBuffer);

  if nReading = 0 then
  Begin
    New(FToPBuffer);
    LineStart := FToPBuffer;
    LineStart^.Nr := 0;
  end;

  FPBuffer^.Nr := nReading;
  FPBuffer^.Str := sBuffer;
  LineStart^.Max := FPBuffer^.Nr;
  FToPBuffer^.Ptr := FPBuffer;
  FToPBuffer := FPBuffer;
end;

begin
  StringList := TStringList.Create;

  Assignfile(ParseFile, Filename);
  reset(ParseFile);

  try
    try
      nReading := 0;
      while not eof(ParseFile) do
      begin
        ReadLN(ParseFile, sBuffer);
        AppendToLinkedList(nReading, sBuffer);
        inc(nReading);
      end;
    except
      raise Exception.Create(SysErrorMessage(GetLastError));
    end;
  finally
    nReading := 0;
    CloseFile(ParseFile);
  end;

  FPBuffer := LineStart;
  while (FPBuffer.Nr <= LineStart.Max - 1) do
  begin
    FPBuffer := FPBuffer.Ptr;
    StringParse := LeftTrim(FPBuffer.Str);
    if Length(StringParse) <> 0 then
      StringList.Add(FPBuffer^.Str);

    if FPBuffer.Nr > 0 then
      if LeftStr(FPBuffer^.Str, 1) = '[then
        StringList.Insert(StringList.IndexOf(StringParse), '');
  end;

  StringList.SaveToFile(Filename);
  StringList.Free;

  { linked List freigeben }
  while LineStart <> nil do begin
    FPBuffer := LineStart;
    LineStart := FPBuffer.Ptr;
    { Bei Dispose kümmert sich der Compiler um das Finalize }
    Dispose(FPBuffer);
  end;
  { keine dangling Pointer hinterlassen }
  FPBuffer := nil;
  FToPBuffer := nil;

end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#6

AW: String freigeben nur wo?

  Alt 18. Feb 2019, 09:24
danke dir Uwe..

Ich habe es vorher mal so versucht.

Delphi-Quellcode:
  if not Assigned(FPBuffer) then
    New(FPBuffer);
  //.....
  finalize(FPbuffer^);
  Dispose(FPBuffer);
  FPBuffer := nil;

  finalize(LineStart^);
  Dispose(LineStart);
  LineStart := nil;
Ist das gleiche Ergebnis wie bei dir.
Ich bin darauf gekommen weil du sagtest
Zitat:
Was mir auffällt ist, daß für jede Zeile im AppendToLinkedList ein New() aufgerufen wird, es aber nur ein einziges Dispose() gibt.
Es ist ja eigentlich nicht nötig jedes mal den FPBuffer neu zu erstellen wenn ich es einmal getan habe.
Doch ist nötig Deshalb nehme ich deine Lösung. Danke noch mal.

Beide Varianten melden jetzt keinen Speicherleck mehr.

Frage mich nur warum beim doppelklick in dem EurekaLog Dialog auf diese zeile gesprungen wird.
AppendToLinkedList(nReading, sBuffer); // sBuffer soll einen Memoryleak produzieren.

das irritiert doch etwas denn sBuffer kann ich dort nicht einfach löschen.

Zitat:
Wenn ich eine Variable als integer definiere dann ist automatisch wenn nichts anderes angegeben wird der erste wert = 0 oder liege ich da falsch?
Falsch.
Nun pauschal kann man das nicht sagen siehe die Erklärung dazu von Uwe.

gruss

Geändert von EWeiss (18. Feb 2019 um 11:14 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
10.989 Beiträge
 
Delphi 12 Athens
 
#7

AW: String freigeben nur wo?

  Alt 18. Feb 2019, 09:54
Es ist ja eigentlich nicht nötig jedes mal den FPBuffer neu zu erstellen wenn ich es einmal getan habe.
Dann gibt es doch aber auch nur einen Record in der linked List, oder?

BTW, warum überhaupt eine linked List? Eine TList<PassenderRecordTyp> ist doch viel einfacher zu handhaben. Das Ptr Feld im Record wäre dann auch obsolet.


Frage mich nur warum beim doppelklick in dem EurekaLog Dialog auf diese zeile gesprungen wird.
AppendToLinkedList(nReading, sBuffer); // sBuffer soll einen Memoryleak produzieren. das irritiert doch etwas denn sBuffer kann ich dort nicht einfach löschen.
Der geleakte Speicher wird halt genau an der Stelle zugewiesen. Der String wird dann dem Record-Feld zugewiesen, was den Referenzzähler erhöht. Die Freigabe von sBuffer gibt dann aber eben nicht den Stringspeicher frei, da dieser ja noch von dem Record-Feld referenziert wird. Erst wenn der Record mit Dispose freigegeben wird, erfolgt auch die Freigabe des Stringspeichers.

Eurekalog kann aber nur erkennen, wo der Speicher alloziert wurde und das ist eben in dieser Zeile.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#8

AW: String freigeben nur wo?

  Alt 18. Feb 2019, 10:00
Sorry Uwe war vorschnell geurteilt
Habe es editiert.

Zitat:
Ist das gleiche Ergebnis wie bei dir.
Ich bin darauf gekommen weil du sagtest
Zitat:
Was mir auffällt ist, daß für jede Zeile im AppendToLinkedList ein New() aufgerufen wird, es aber nur ein einziges Dispose() gibt.
Es ist ja eigentlich nicht nötig jedes mal den FPBuffer neu zu erstellen wenn ich es einmal getan habe.
Doch ist nötig Deshalb nehme ich deine Lösung. Danke noch mal.
Zitat:
BTW, warum überhaupt eine linked List? Eine TList<PassenderRecordTyp> ist doch viel einfacher zu handhaben. Das Ptr Feld im Record wäre dann auch obsolet.
Na ja NonVcl halt wenn nicht unbedingt nötig verwende ich die Win32API.

gruss

Geändert von EWeiss (18. Feb 2019 um 11:15 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#9

AW: String freigeben nur wo?

  Alt 18. Feb 2019, 10:08
Zitat:
BTW, warum überhaupt eine linked List? Eine TList<PassenderRecordTyp> ist doch viel einfacher zu handhaben. Das Ptr Feld im Record wäre dann auch obsolet.
Na ja NonVcl halt wenn nicht unbedingt nötig verwende ich die Win32API.
TList<T> ist NonVCL
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#10

AW: String freigeben nur wo?

  Alt 18. Feb 2019, 10:11
Zitat:
BTW, warum überhaupt eine linked List? Eine TList<PassenderRecordTyp> ist doch viel einfacher zu handhaben. Das Ptr Feld im Record wäre dann auch obsolet.
Na ja NonVcl halt wenn nicht unbedingt nötig verwende ich die Win32API.
TList<T> ist NonVCL
Du hast recht
Habe es nun mal so gemacht.
Und mit Uwes Hilfe wird jetzt alles korrekt frei gegeben.

Danke nochmals.

gruss
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 09:25 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