Speicherfreigabe bei Listen

Für allgemeine Fragen zur Programmierung mit PureBasic.
fabulouspaul
Beiträge: 120
Registriert: 01.04.2011 21:59

Speicherfreigabe bei Listen

Beitrag von fabulouspaul »

Hallo zusammen,

ich bastle gerade etwas herum, um bestimmte Informationen mit einem "Zeitstempel" in einer Queue zu verwalten. Nach einer gewissen Zeit soll die Information ungültig werden und aus der Queue gelöscht werden.
Ich habe mir eine Struktur mit den nötigen Datentypen angelegt und mit NewList() eine entsprechende Liste erzeugt.
Jede Sekunde wird nun die Liste durchgeschaut, ob Elemente gelöscht werden können (DeleteElement()).

Wenn ich mir den Taskmanager dazunehme, wächst die Liste zwar mit den neuen Elementen jeweils an, aber der Speicherplatz wird nach dem Löschen nicht wieder freigegeben. Selbst wenn alle Elemente mit DeleteElement() gelöscht wurden, bleibt der Speicherverbrauch konstant. Wenn dann wieder ein Element hinzugefügt wird, wird erneut Speicher verbraucht, so dass irgendwann der Speicher vollläuft.

Mache ich was falsch oder ist das einfach so?

Grüße Paul
Benutzeravatar
CSHW89
Beiträge: 489
Registriert: 14.12.2008 12:22

Re: Speicherfreigabe bei Listen

Beitrag von CSHW89 »

Ohne Code lässt sich da wenig sagen. Normalerweise allokiert PB einen Speicherbereich für eine Liste, in dem über 1000 Elemente oder so gespeichert werden können. Dieser wird nur dann vergrößert, wenn man mehr Elemente reinhaut. Wenn Elemente gelöscht werden, ist in diesem Speicherbereich wieder Platz frei. Der Speicher selbst wird aber nicht freigegeben. Allerdings sollte nicht nochmal Speicher allokiert werden, wenn man dann in die leere Liste Elemente reintut.
Also scheint da was nicht zu stimmten. Allokierst du selbst mit AllocateMemory Speicher? Irgendein verpfuschen von Strings wäre auch noch denkbar. Aber wie gesagt, ohne Code keine Möglichkeit zu helfen.

lg Kevin
Bild Bild Bild
http://www.jasik.de - Windows Hilfe Seite
padawan hat geschrieben:Ich liebe diese von hinten über die Brust ins Auge Lösungen
fabulouspaul
Beiträge: 120
Registriert: 01.04.2011 21:59

Re: Speicherfreigabe bei Listen

Beitrag von fabulouspaul »

Ich allokiere keinen Speicher über die Memory-Befehle, es läuft alles über die Liste.

Hier mein (etwas unaufgeräumter) Code:

Code: Alles auswählen

EnableExplicit

;- Window Constants
;
Enumeration
  #Main_Window
EndEnumeration

;- Gadget Constants
;
Enumeration
  #Button_0
  #Button_1
  #Frame3D_0
  #ListIcon_1
EndEnumeration

;- StatusBar Constants
;
Enumeration
  #StatusBar_1
EndEnumeration

Procedure Open_Main_Window()
  If OpenWindow(#Main_Window, 364, 223, 583, 555, "Queue-Spielerei",  #PB_Window_SystemMenu | #PB_Window_TitleBar )
    If CreateStatusBar(#StatusBar_1, WindowID(#Main_Window))
      AddStatusBarField(380)
      AddStatusBarField(200)
      StatusBarText(#StatusBar_1, 0, "")
      StatusBarText(#StatusBar_1, 1, "")
    EndIf
    
    If CreateGadgetList(WindowID(#Main_Window))
      ButtonGadget(#Button_0, 470, 0, 110, 30, "Ende")
      ButtonGadget(#Button_1, 0, 0, 110, 30, "Element hinzufügen")
      Frame3DGadget(#Frame3D_0, 0, 40, 580, 490, "Queue-Inhalt")
      
      ;-
      ListIconGadget(#ListIcon_1, 10, 60, 562, 460, "IP-Adresse", 100, #PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
      AddGadgetColumn(#ListIcon_1, 1, "Port", 50)
      AddGadgetColumn(#ListIcon_1, 2, "Client-Name", 120)
      AddGadgetColumn(#ListIcon_1, 3, "Client-Typ", 100)
      AddGadgetColumn(#ListIcon_1, 4, "Token", 80)
      AddGadgetColumn(#ListIcon_1, 5, "Letzter Kontakt", 90)
      
    EndIf
  EndIf
EndProcedure


Structure queue         ; Struktur der Queue
  IPAdresse.s           ; IP-Adresse des Clients
  Port.i                ; Port des Clients
  Clientname.s          ; Name des Clients
  Clienttype.i          ; Art des Clients (1 = Supplier, 2 = Worker)
  Clienttoken.i         ; ID-Token des Clients
  Lastcontact.i         ; Letztes "Lebenssignal" des Clients
EndStructure

Global NewList client.queue()   ; Client-Queue anlegen
Global Dim clienttyp.s(2)       ; Klarschrift des Client-Typs
Global alive                    ; Zeit in Sek. in der der Client ein Lebenssignal abgeben muss

Global Event, WindowID, GadgetID, EventType
Global exitloop

Declare init()
Declare refresh_list()
Declare delete_outdated()

Open_Main_Window()
init()
exitloop = 0

Repeat ; Start of the event loop
  
  Event = WaitWindowEvent(1000)         ; Auf einen Windows-Event warten oder nach 1 Sek. weitermachen
  WindowID = EventWindow()              ; Aus welchem Fenster kommt der Event?
  GadgetID = EventGadget()              ; Ist es ein gadget-Event?
  EventType = EventType()               ; Was ist es für ein Event-Typ?
   
  If delete_outdated() = 1              ; Abgelaufene Einträge entfernen
    refresh_list()                      ; ...und wenn Einträge entfernt wurden, Listenanzeige auffrischen
  EndIf
  
  If Event = #PB_Event_Gadget
    
    If GadgetID = #Button_1             ; Eintrag hinzufügen
      AddElement(client())
      client()\IPAdresse = Right("000" + Str(Random(255)),3) + "." + Right("000" + Str(Random(255)),3) + "." + Right("000" + Str(Random(255)),3) + "." + Right("000" + Str(Random(255)),3)
      client()\Port = Random(65535)
      client()\Clientname = "Test_" + Str(ListSize(client()))
      client()\Clienttype = Random(2)
      client()\Clienttoken = Random(9999999999)
      client()\Lastcontact = Date()
      
      refresh_list()                    ; Listenanzeige auffrischen
      
    ElseIf GadgetID = #Button_0         ; Ende
      exitloop = 1
    EndIf
    
  EndIf
  
Until Event = #PB_Event_CloseWindow Or exitloop = 1 ; End of the event loop
End

Procedure init()
  clienttyp(0) = "*undefiniert*"
  clienttyp(1) = "Supplier"
  clienttyp(2) = "Worker"  
  
  alive = 10
EndProcedure

Procedure refresh_list()
  ClearGadgetItems(#ListIcon_1)
  FirstElement(client())
  ForEach client()  
    AddGadgetItem(#ListIcon_1, -1, client()\IPAdresse + Chr(10) + Str(client()\Port) + Chr(10) + client()\Clientname + Chr(10) + clienttyp(client()\Clienttype) + Chr(10) + Str(client()\Clienttoken) + Chr(10) + Str(client()\Lastcontact)) 
  Next
  StatusBarText(#StatusBar_1, 0, Str(ListSize(client())))
EndProcedure

Procedure delete_outdated()
  Protected action
  
  action = 0
  FirstElement(client())
  ForEach client()
    If Date() > client()\Lastcontact + alive 
      DeleteElement(client())
      action = 1
    EndIf
  Next
  ProcedureReturn action
EndProcedure
Man kann am Taskmanager gut verfolgen wie mit jedem hinzufügen eines Elements der belegte Speicher steigt, wenn Elemente rausfallen wird der Speicherbedarf nicht geringer. Das wäre auch OK, wenn der Speicherbedarf dann konstant bliebe wenn nach dem Löschen neue Elemente hinzukommen...
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Speicherfreigabe bei Listen

Beitrag von RSBasic »

Ob es mit meiner Methode sinnvoll ist, weiß ich zwar nicht, aber du könntest dafür sorgen, dass Windows dein Speicher bereinigt (WinAPI):

Code: Alles auswählen

EnableExplicit

;- Window Constants
;
Enumeration
  #Main_Window
EndEnumeration

;- Gadget Constants
;
Enumeration
  #Button_0
  #Button_1
  #Button_2
  #Frame3D_0
  #ListIcon_1
EndEnumeration

;- StatusBar Constants
;
Enumeration
  #StatusBar_1
EndEnumeration

Procedure freeWorkingMemory()
  Protected myProcessID,PHandle,Result
  
  myProcessID=GetCurrentProcessId_()
  PHandle = GetCurrentProcess_()
 
  Result= SetProcessWorkingSetSize_(PHandle,-1,-1)
  If Result
   
  Else
    ; it failed
  EndIf
  
EndProcedure

Procedure Open_Main_Window()
  If OpenWindow(#Main_Window, 364, 223, 583, 555, "Queue-Spielerei",  #PB_Window_SystemMenu | #PB_Window_TitleBar )
    If CreateStatusBar(#StatusBar_1, WindowID(#Main_Window))
      AddStatusBarField(380)
      AddStatusBarField(200)
      StatusBarText(#StatusBar_1, 0, "")
      StatusBarText(#StatusBar_1, 1, "")
    EndIf
   
    If CreateGadgetList(WindowID(#Main_Window))
      ButtonGadget(#Button_0, 470, 0, 110, 30, "Ende")
      ButtonGadget(#Button_1, 0, 0, 110, 30, "Element hinzufügen")
      ButtonGadget(#Button_2, 200, 0, 110, 30, "Speicher bereinigen")
      Frame3DGadget(#Frame3D_0, 0, 40, 580, 490, "Queue-Inhalt")
     
      ;-
      ListIconGadget(#ListIcon_1, 10, 60, 562, 460, "IP-Adresse", 100, #PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
      AddGadgetColumn(#ListIcon_1, 1, "Port", 50)
      AddGadgetColumn(#ListIcon_1, 2, "Client-Name", 120)
      AddGadgetColumn(#ListIcon_1, 3, "Client-Typ", 100)
      AddGadgetColumn(#ListIcon_1, 4, "Token", 80)
      AddGadgetColumn(#ListIcon_1, 5, "Letzter Kontakt", 90)
     
    EndIf
  EndIf
EndProcedure


Structure queue         ; Struktur der Queue
  IPAdresse.s           ; IP-Adresse des Clients
  Port.i                ; Port des Clients
  Clientname.s          ; Name des Clients
  Clienttype.i          ; Art des Clients (1 = Supplier, 2 = Worker)
  Clienttoken.i         ; ID-Token des Clients
  Lastcontact.i         ; Letztes "Lebenssignal" des Clients
EndStructure

Global NewList client.queue()   ; Client-Queue anlegen
Global Dim clienttyp.s(2)       ; Klarschrift des Client-Typs
Global alive                    ; Zeit in Sek. in der der Client ein Lebenssignal abgeben muss

Global Event, WindowID, GadgetID, EventType
Global exitloop

Declare init()
Declare refresh_list()
Declare delete_outdated()

Open_Main_Window()
init()
exitloop = 0

Repeat ; Start of the event loop
 
  Event = WaitWindowEvent(1000)         ; Auf einen Windows-Event warten oder nach 1 Sek. weitermachen
  WindowID = EventWindow()              ; Aus welchem Fenster kommt der Event?
  GadgetID = EventGadget()              ; Ist es ein gadget-Event?
  EventType = EventType()               ; Was ist es für ein Event-Typ?
   
  If delete_outdated() = 1              ; Abgelaufene Einträge entfernen
    refresh_list()                      ; ...und wenn Einträge entfernt wurden, Listenanzeige auffrischen
  EndIf
 
  If Event = #PB_Event_Gadget
   
    If GadgetID = #Button_1             ; Eintrag hinzufügen
      AddElement(client())
      client()\IPAdresse = Right("000" + Str(Random(255)),3) + "." + Right("000" + Str(Random(255)),3) + "." + Right("000" + Str(Random(255)),3) + "." + Right("000" + Str(Random(255)),3)
      client()\Port = Random(65535)
      client()\Clientname = "Test_" + Str(ListSize(client()))
      client()\Clienttype = Random(2)
      client()\Clienttoken = Random(9999999999)
      client()\Lastcontact = Date()
     
      refresh_list()                    ; Listenanzeige auffrischen
      
      
    ElseIf GadgetID = #Button_0         ; Ende
      exitloop = 1
    ElseIf GadgetID = #Button_2
      freeWorkingMemory()
    EndIf
   
  EndIf
 
Until Event = #PB_Event_CloseWindow Or exitloop = 1 ; End of the event loop
End

Procedure init()
  clienttyp(0) = "*undefiniert*"
  clienttyp(1) = "Supplier"
  clienttyp(2) = "Worker" 
 
  alive = 10
EndProcedure

Procedure refresh_list()
  ClearGadgetItems(#ListIcon_1)
  FirstElement(client())
  ForEach client() 
    AddGadgetItem(#ListIcon_1, -1, client()\IPAdresse + Chr(10) + Str(client()\Port) + Chr(10) + client()\Clientname + Chr(10) + clienttyp(client()\Clienttype) + Chr(10) + Str(client()\Clienttoken) + Chr(10) + Str(client()\Lastcontact))
  Next
  StatusBarText(#StatusBar_1, 0, Str(ListSize(client())))
EndProcedure

Procedure delete_outdated()
  Protected action
 
  action = 0
  FirstElement(client())
  ForEach client()
    If Date() > client()\Lastcontact + alive
      DeleteElement(client())
      action = 1
    EndIf
  Next
  
  
  ProcedureReturn action
EndProcedure
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
fabulouspaul
Beiträge: 120
Registriert: 01.04.2011 21:59

Re: Speicherfreigabe bei Listen

Beitrag von fabulouspaul »

Hmmm, ist nicht ganz da, was ich mir vorgestellt habe, aber die Speicherbereinigung über die API sieht doch erstmal gut aus! :wink:
Wenn ich nicht manuell bereinige, sondern immer dann, wenn Elemente aus der Liste gelöscht wurden, dann sollte der Speicher eigentlich nicht voll laufen.

Prima, das hilft mir!
DANKE! :allright:
Benutzeravatar
CSHW89
Beiträge: 489
Registriert: 14.12.2008 12:22

Re: Speicherfreigabe bei Listen

Beitrag von CSHW89 »

Ich kann die Speicherzumüllung übrigens nicht bestätigen. Die Speicheranzeige ist ja ein bisschen träge. Wenn man da ein bisschen wartet, geht der Verbrauch auch wieder zurück. Zumindest bei mir.

lg Kevin
Bild Bild Bild
http://www.jasik.de - Windows Hilfe Seite
padawan hat geschrieben:Ich liebe diese von hinten über die Brust ins Auge Lösungen
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Speicherfreigabe bei Listen

Beitrag von Nino »

Das hört sich nach dem gleichen "Problem" an, wie es hier beschrieben wurde: http://www.purebasic.fr/english/viewtop ... 13&t=50449
freak hat geschrieben:Never trust programs like the task manager about such things. As long as there is no immediate need for the freed memory, the OS will usually keep it reserved for the program for a possible later allocation. So the number doesn't go down immediately. That doesn't mean that the memory is actually still allocated by the program.
Grüße, Nino
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Re: Speicherfreigabe bei Listen

Beitrag von PMV »

Sinngemäß übersetzt heißt das, das du die Linked Liste ruhig benutzen
kannst und dir nichts darauf geben solltest, was Windows im Task Manager
zeigt. :wink:

MFG PMV
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
Antworten