AGB  ·  Datenschutz  ·  Impressum  







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

Speicherproblem mit Dispose

Ein Thema von me2u · begonnen am 3. Mai 2007 · letzter Beitrag vom 3. Mai 2007
Antwort Antwort
me2u
(Gast)

n/a Beiträge
 
#1

Speicherproblem mit Dispose

  Alt 3. Mai 2007, 02:59
Hallo zusammen,

ich habe hier ein kleines "Speicherproblem", dessen Ursache ich mir nicht so genau erklären kann: Das Programm besteht aus einer einfach verketteten Liste, die auf Knopfdruck mit 50000 Elementen gefüllt wird und ebenfalls auch wieder auf Knopfdruck entleert werden kann.
Sofort nach Programmstart benötigt das Programm ca. 3.500K Speicher. Nach dem Befüllen ca. 16.100K und nun das seltsame... nach dem Entleeren der Liste immer noch ca. 7300K. Warum fällt der Speicherbedarf nach dem entleeren der Liste nicht wieder auf die ursprünglichen 3500K zurück (oder zumindest annähernd auf diesen Wert)? Ist es ein Programmierfehler, den ich übersehe?

MfG
Markus

Hier mal der Code:

Delphi-Quellcode:
type
  [...]
  PRegEntry = ^TRegEntry;
  TRegEntry = record
    Key: Cardinal;
    KeyName: string;
    next: PRegEntry;
  end;

var
  Form1: TForm1;
  RegListAnchor: PRegEntry;

[...]

function GetKeyName(hKey: HKEY): string;
var now: PRegEntry;
begin
  Result := 'Error';
  if (RegListAnchor <> nil)
    then begin
      now := RegListAnchor;
      while (now^.next <> nil) and (now^.Key <> hKey) do
        now := now^.next;
      if now^.Key = hKey then Result := now^.KeyName;
    end;
end;

function AddRegEntry(const hKey: HKEY; KeyName: string): Boolean;
var now, newEntry: PRegEntry;
begin
  Result := False;
  if RegListAnchor = nil
  then begin // noch kein Eintrag in der Socket-Liste
    New(newEntry);
    newEntry^.Key := hKey;
    newEntry^.KeyName := KeyName;
    newEntry^.Next := nil;
    RegListAnchor := newEntry;
    Result := True;
  end
  else begin // schon Elemente in der Socket-Liste
      now := RegListAnchor;
      while (now^.next <> nil) and (now^.Key <> hKey) do
        now := now^.next;
      if now^.Key = hKey
      then begin
        now^.KeyName := KeyName;
        Result := True;
      end
      else begin
        New(newEntry);
        newEntry^.Key := hKey;
        newEntry^.KeyName := KeyName;
        newEntry^.Next := RegListAnchor;
        RegListAnchor := newEntry;
        Result := True;
      end;
    end;
end;

function DeleteRegEntry(hKey: HKEY): Boolean;
var davor, pos: PRegEntry;
begin
  Result := False;
    if (RegListAnchor <> nil) // nur löschen, wenn überhaupt Einträge in Liste
    then begin
      pos := RegListAnchor;
      if RegListAnchor^.Key = hKey // 1.Element = zu löschender Eintrag ?
      then begin
        RegListAnchor := RegListAnchor^.next;
        Dispose(pos);
        Result := True;
      end
      else begin // zu löschender Eintrag is nich Listenanfang
        if RegListAnchor^.next <> nil // wenn nur ein Eintrag und der verschieden von zu löschendem Element is => Nix zu löschen
        then begin
          pos := RegListAnchor^.next;
          davor := RegListAnchor;
          while (pos^.next <> nil) and (pos^.Key <> hKey) do begin
            davor := pos;
            pos := pos^.next;
          end;
          if pos^.Key = hKey then begin
            davor^.next := pos^.next;
            Dispose(pos);
            Result := True;
          end;
        end;
      end;
    end;
end;

function GetAllEntries: string;
var pos: PRegEntry;
begin
  Result := '{';
  if (RegListAnchor <> nil)
  then begin
    pos := RegListAnchor;
    while pos<>nil do begin
      if Result = '{'
      then Result := Result + IntToStr(pos^.Key)
      else Result := Result + ', ' + IntToStr(pos^.Key);
      pos := pos^.next;
    end;
  end;
  Result := Result + '}';
end;

[...]

procedure TForm1.Button1Click(Sender: TObject);
var i: Integer;
begin
  Memo1.Lines.Clear;
  for i := 1 to 50000 do begin
    AddRegEntry(i, 'MAiluglugklhgkhvljhblkjhigjhvb,jhvkhgfljghgizt975hgkhhitz59hgjkhkgvnbvkhgfkghvb kvfghkjlhzgulzguzgut67tuzhgkjbh87thujbljhb87tzjhbjhb8tjhbkuzg87jhbo87tiuhb,jhg8o7tjlhbo87tvkghvkuzgvhb khgvkvb kgvuvrkus');
  end;
  Memo1.Lines.Clear;
  Memo1.Lines.Add(GetAllEntries);
end;

procedure TForm1.Button2Click(Sender: TObject);
var i: Integer;
begin
  Memo1.Lines.Clear;
  for i := 50000 downto 1 do DeleteRegEntry(i);
  Memo1.Lines.Clear;
  Memo1.Lines.Add(GetAllEntries);
end;
  Mit Zitat antworten Zitat
akrichel

Registriert seit: 7. Jun 2006
3 Beiträge
 
Delphi XE5 Professional
 
#2

Re: Speicherproblem mit Dispose

  Alt 3. Mai 2007, 07:24
Hi !

Du hast kein Speicherproblem.
Deine Methoden und auch das Dispose funktionieren einwandfrei.

Schuld ist TMemo bzw. die darin gekapselte Stringliste. Fülle mal 50000 Einträge in ein Memo bzw. eine Stringliste und mache dann ein Clear. Dann bleibt der im Memo reservierte Speicher weiter reserviert (damit landest Du bei 50000 Einträgen übrigens bei ca. 7300k). Mit dem Clear wird der Count=0 aber die "Kapazität" der Liste bleibt erhalten.

MfG
Alex
  Mit Zitat antworten Zitat
Benutzerbild von OldGrumpy
OldGrumpy

Registriert seit: 28. Sep 2006
Ort: Sandhausen
941 Beiträge
 
Delphi 2006 Professional
 
#3

Re: Speicherproblem mit Dispose

  Alt 3. Mai 2007, 09:05
Das ist ja auch gut so, damit wird einer massiven Fragmentierung des Heaps vorgebeugt. Vor ein paar Wochen hatte ich hier eine "hochoptimiert speichersparende" Geschichte vorliegen, das war wirklich nicht schön mit anzusehen. Der Speicherbedarf war zwar nicht so gross, aber weil andauernd Speicherblöcke unterschiedlichster Größe freigegeben und neu angefordert wurden, sahs nach einem Tag Laufzeit aus wie auf nem Minenfeld. Das wirkte sich dann langfristig gesehen auch deutlich negativ auf die Performance aus. Ich hab dann mit einem einfachen Handgriff das ganze mal spürbar optimiert, indem ich die Speicherblöcke selber verwalte und nur freigebe wenns wirklich sinnvoll ist. Dadurch vergrößerte sich zwar der Speicherbedarf aber im Zeitalter von Hauptspeicher im Gigabytebereich zählt Performance und Langzeitstabilität mehr als ein paar MB Speicherbedarf.
"Tja ja, das Ausrufezeichen... Der virtuelle Spoiler des 21. Jahrhunderts, der Breitreifen für die Datenautobahn, die k3wle Sonnenbrille fürs Usenet. " (Henning Richter)
  Mit Zitat antworten Zitat
akrichel

Registriert seit: 7. Jun 2006
3 Beiträge
 
Delphi XE5 Professional
 
#4

Re: Speicherproblem mit Dispose

  Alt 3. Mai 2007, 09:13
Nunja, ich habe ja auch nicht gesagt dass dies gut oder schlecht ist.
Je nach Nutzung kann das durchaus positiv sein (wie Du ja auch beschreibst) oder wie in dem Fall vielleicht nicht ganz so schön sein (Tip: wenn man in einer Stringliste nicht clear aufruft sondern die Elemente deleted, dann wird der Speicher auch freigegeben. Delete vom letzten Element an bietet sich aus Geschwindigkeitsgründen an).

Ich wollte nur erklären dass es nicht am Dispose liegt und kein Programmierfehler bei dem Umgang mit den Pointern ist (was wirklich zu einem Speicherproblem führen würde wenn Leaks entstehen). Ich glaube, das wollte Markus auch wissen.

MfG

Alex
  Mit Zitat antworten Zitat
xaromz

Registriert seit: 18. Mär 2005
1.682 Beiträge
 
Delphi 2006 Enterprise
 
#5

Re: Speicherproblem mit Dispose

  Alt 3. Mai 2007, 09:43
Hallo,
Zitat von akrichel:
(Tip: wenn man in einer Stringliste nicht clear aufruft sondern die Elemente deleted, dann wird der Speicher auch freigegeben. Delete vom letzten Element an bietet sich aus Geschwindigkeitsgründen an).
Das ist so nicht ganz richtig. Die Methode TStringList.Clear sieht folgendermaßen aus:
Delphi-Quellcode:
  if FCount <> 0 then
  begin
    Changing;
    Finalize(FList^[0], FCount);
    FCount := 0;
    SetCapacity(0);
    Changed;
  end;
Es werden also sowohl die Strings als auch die Liste freigegeben. Das Problem ist eher, dass TMemo.Lines keine TStringList ist, sondern eine eigene Implementierung der abstrakten Klasse TStrings. TMemo ist nämlich nur ein Wrapper um ein Windows-Control, welches den Speicher für seinen Inhalt selbst verwaltet.

Gruß
xaromz
I am a leaf on the wind - watch how I soar
  Mit Zitat antworten Zitat
akrichel

Registriert seit: 7. Jun 2006
3 Beiträge
 
Delphi XE5 Professional
 
#6

Re: Speicherproblem mit Dispose

  Alt 3. Mai 2007, 10:01
Hallo xaromz,

da hast Du völlig Recht.
Ich habe mich mit 'Stringlist' auch blöd ausgedrückt.

Gruß,
Alex
  Mit Zitat antworten Zitat
Udontknow

Registriert seit: 17. Jun 2002
223 Beiträge
 
#7

Re: Speicherproblem mit Dispose

  Alt 3. Mai 2007, 10:09
Hallo!

Das "Problem" ist doch ein grundsätzliches und wurde auch schon häufiger hier besprochen: Der Delphi-Speichermanager gibt Speicher nicht einfach wieder frei, sobald man Free/Destroy/Delete/Dispose/Freemem von irgendwelchen Objekten etc. aufruft. Er hält stattdessen den Speicher im Zugriff, um bei New/Create/Getmem etc. erneute Calls an das Betriebssystem für die Reservierung von Speicher zu vermeiden.

It´s not a bug, it´s a feature!

Cu,
Udontknow
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.270 Beiträge
 
Delphi 10.4 Sydney
 
#8

Re: Speicherproblem mit Dispose

  Alt 3. Mai 2007, 10:27
Hallo,

FastMM oder memproof zeigen an,
ob nicht doch Speicher verbraten wird.


Heiko
Heiko
  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 17:06 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