Seite 1 von 1

Speicherfreigabe bei Listen

Verfasst: 08.07.2012 18:32
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

Re: Speicherfreigabe bei Listen

Verfasst: 08.07.2012 18:45
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

Re: Speicherfreigabe bei Listen

Verfasst: 08.07.2012 18:54
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...

Re: Speicherfreigabe bei Listen

Verfasst: 08.07.2012 19:03
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

Re: Speicherfreigabe bei Listen

Verfasst: 08.07.2012 19:15
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:

Re: Speicherfreigabe bei Listen

Verfasst: 08.07.2012 19:25
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

Re: Speicherfreigabe bei Listen

Verfasst: 08.07.2012 19:36
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

Re: Speicherfreigabe bei Listen

Verfasst: 08.07.2012 23:32
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