Seite 3 von 5

Verfasst: 23.01.2006 21:18
von helpy
Hi ts-soft,
ts-soft hat geschrieben:PB gibt am Programmende den kompletten Stringspeicher frei, ...
JA! Stimmt!
ts-soft hat geschrieben:... sowie alle anderen Speicher auch.
JA! Stimmt!
ts-soft hat geschrieben:Strings können während des Programmlaufs nur durch Zuweisung eines Nullstrings ("") gelöscht werden.
Das stimmt so nicht ganz! Der String ist zwar leer! Aber es ist immer noch Speicherplatz für den String reserviert! Das kann man mit folgendem Test nachweisen:

Code: Alles auswählen

MessageRequester("test","Start of Program")
; =>   2.4 MByte
Dim aString.s(1024*1024)
MessageRequester("test","Dim aString.s(1024*1024)")
; =>   2.5 MByte
For i = 0 To 1024*1024
	aString.s(i) = "Test String"
Next i
MessageRequester("test","Array filled with Strings")
; =>  23.0 MByte
For i = 0 To 1024*1024
	aString.s(i) = ""
Next i
MessageRequester("test","Strings in Array are cleared with NULL string")
; =>  23.0 MByte
Dim aString.s(0)
MessageRequester("test","Array is set to size ZERO!")
; =>   2.6 MByte
Die angegebenen Werte stellt die im Taskmanager angezeigte Speicherauslastung des Programmes dar (jeweils abgelesen, wenn die MessageBox erscheint).

Da ist zu erkennen, dass der Speicherverbrauch nicht höher ist, gleichgültig ob die einzelnen Array-Elemente mit dem String "test" oder mit dem Null-String "" gefüllt wurden. D.h. Auch ein Nullstring braucht eine bestimmte Menge an Speicherplatz!

Erst wenn das ganze Array gelöscht wird, wird auch der Speicherplatz für die Strings freigegeben.
ts-soft hat geschrieben:Im Zweifelsfalle mach einfach FreeMemory(#PB_Any)
Stell Dir vor Du hast mehrere dynamisch allokierte Speicherbereiche und willst nur einen davon freigeben! Um die Daten der anderen Speicherbereiche nicht zu verlieren, kann ich FreeMemory(#PB_Any) nicht verwendet.

JA! Beim Programmende wird Speicher wieder freigegeben! Aber stell Dir eine Anwendung vor, die einen ganzen Tag (oder auf einem Server sogar mehrere Tage) läuft, dann muss eine eigene Aufräumroutine geschrieben werden, die es ermöglicht dynamisch erzeugte Strukturvariablen mit Strings wieder freizugeben. Anders sehe ich zur Zeit keinen Ausweg!

Beispiel:

Code: Alles auswählen

#TEST_LOOP = 1024*1024

Structure TEST_STRUCT
   ps.l
   x.l
   y.l
EndStructure

Procedure CreateString(*s)
	Protected PointerToString, LenOfString
	LenOfString = MemoryStringLength(*s)
	PointerToString = AllocateMemory(LenOfString+1)
	If PointerToString <> 0
		CopyMemory(*s,PointerToString,LenOfString)
	EndIf
	ProcedureReturn PointerToString
EndProcedure

Dim *test.TEST_STRUCT(#TEST_LOOP)
MessageRequester("TEST","Array is ready!")
For i = 1 To #TEST_LOOP
   *test(i) = AllocateMemory(SizeOf(TEST_STRUCT))
   If *test(i) <> 0
      *test(i)\ps = CreateString(@"Ein Test")
   EndIf
Next i
MessageRequester("TEST","Memory allocated and assigned to array!")

Debug PeekS(*test(1)\ps)
Debug PeekS(*test(1000)\ps)
Debug PeekS(*test(1000000)\ps)

For i = 1 To #TEST_LOOP
	FreeMemory( *test(i)\ps )
	FreeMemory( *test(i) )
Next i
MessageRequester("TEST","Memory is free again!")
Das funktioniert so recht gut! Nachteil ist, dass man auf die Strings über Peeks zugreifen muss.

Die Funktion von remi_meier scheint auch zu funktionieren. Gibt es jedoch mehrere Strings in einer Struktur, muss die Funktion FreeStructuredString auch für jedes Struktur-Element vom Typ String aufgerufen werden!

cu, helpy

Verfasst: 23.01.2006 21:25
von ts-soft
Immer ich :lol:
Ich hab das Problem so noch nicht gehabt. Lediglich die 63999 Einschränkung hat mich des öfteren behindert.

Vielleicht werde ich ja auch mal ne komplette Datenbanken im Speicher händeln, aber im Moment hab ich keinen Bedarf :mrgreen:

Verfasst: 23.01.2006 21:45
von helpy
ts-soft hat geschrieben:Immer ich :lol:
uups ... :oops:

Hoffe ich bin sachlich geblieben :?:

cu, helpy

Verfasst: 23.01.2006 22:09
von ts-soft
helpy hat geschrieben: Hoffe ich bin sachlich geblieben :?:

cu, helpy
Keine Sorge Bild

Verfasst: 23.01.2006 22:22
von PMV
Ich bleib lieber erst mal bei dem ohne ASM ... da weis ich wenigstens was passiert :D .

Aber danke remi.
Gibt es eigentlich einen Geschwindigkeitsunterschied wenn man PeekS() verwendet anstelle eine Stringvariable auf zu rufen?

MFG PMV

Verfasst: 23.01.2006 22:57
von MVXA
@remi_meier
Funktioniert hier sehr gut. Wäre genial, wenn Fread so eine Funktion
wie [c]FreeStructure()[/c] einbauen würde.

Verfasst: 24.01.2006 11:49
von NicTheQuick
@Friedrichs:
Ich würde die Version von remi_meier nehmen, da sie richtig funktioniert.
In meiner TreeLinkedList habe ich es anscheinend irgendwie anders
gelöst, aber ich weiß bis heute nicht, was daran so besonders war. Auf
jeden Fall hat es auch immer die Strings komplett aus dem Speicher
gelöscht.

Verfasst: 24.01.2006 18:56
von remi_meier
Was auch geht und gleich die ganze Struktur von Strings mit einem Befehl
befreit:

Code: Alles auswählen

OpenConsole() 
Structure TestStruc 
   l.l 
   s.s 
   f.f
   s2.s 
EndStructure 

; Beliebig viele Offsets der Strings in der Struktur mit abschliessendem -1
DataSection
offTestStruc:
Data.l OffsetOf(TestStruc\s), OffsetOf(TestStruc\s2), -1
EndDataSection


Procedure FreeStructuredStrings(ptrstruct.l, ptroffsets.l) 
  !PUSH dword [esp+4] ; offsets der Strings
  !PUSH dword [esp+4] ; ptrstruct 
  !CALL _SYS_FreeStructureStrings@8
EndProcedure 


For i = 1 To 100000 
   Elemente.l = 10 ;Anzahl der Element 
   *pArray = AllocateMemory(SizeOf(TestStruc) * Elemente) ;Speicher resevieren fr alle Elemente 
   *pElement.TestStruc = *pArray ;Pointer zum Speichern dem ersten Element bergeben 
   ;Print(Str(i)) 
   For a.l = 1 To Elemente ;Elemente fllen 
      *pElement\l = Elemente + 1 - a 
      *pElement\s = "Zahl: " + Str(a) + "-------------------------------------------------------------" 
      *pElement\s2 = "dasklfjas"
      *pElement\f = 1 / a 
      *pElement + SizeOf(TestStruc) 
   Next 
    
   *pElement = *pArray ;Erstes Element wieder auswhlen 
   For a.l = 1 To Elemente ;Elemente auslesen 
      FreeStructuredStrings(*pElement, ?offTestStruc) 
      *pElement + SizeOf(TestStruc) 
   Next 
   FreeMemory(*pArray) ;Array wieder freigeben 
Next i 

For i = 1 To 100 
Delay(100) 
Next i 
CloseConsole()
So kann für jede Struktur eine Datasection mit Stringoffsets gemacht
werden um dann mit einer Funktion alle Strings zu 'entfernen'.
Ev. nützlicher :)

Verfasst: 24.01.2006 18:59
von NicTheQuick
Gute Sache! :allright:

Sollte unter "Codes, Tipps & Tricks"!

Verfasst: 24.01.2006 19:33
von Toshy
also das mit dem "einzelnen" löschen klappt anscheinend. das andere muß ich noch testen. jetzt muß ich das nur noch verstehen (besonders die ganze struktur freizugeben).

aber ein problem habe ich noch, das hatte ich vorher wohl so erklärt, das es nicht verstanden wurde.

Also der Reihe nach:
PB gibt den Speicher korretk frei, solange man die Struktur an der Origianlstelle neu schreibt. Auf jeden Fall hat es den Anschein.
Es gäbe zwei Gründe warum der speicher nicht verloren geht. Erstens weil immer der der selbe (String)speicher überschrieben wird (glaube ich nicht, weil dann könnte man keine memorybereich füllen) oder es wird einfach der alte string(speicher) gelöscht anhand der alten daten, also dem pointer in der struktur.
Wenn dem so ist, dann müßte es so sein, das aus dem speicher der pointer ausgelesen wird (wie man es auch mit peek machen könnte) und dann über diesen pointer der string freigegeben wird.
So wie es "remi_meier" in seinem Code macht, nur halt PB-initern.

Wenn dem aber so ist, dann besteht da eine Gefahr!
Ich lege jetzt also einen Speicherbereich an (memory) und schreibe ihn diesen mit hilfe einer structure daten. soweit ok. aber beim schreiben der struktur gibt pb ja den speicher des ungültig werdenen string frei. diesen ermittelt pb wohl anhand des pointers. diesen erhält es aus dem memorybereich. ok, hat m an einen neu angelegten bereich, dann ist der wert NULL. da wird dann warhscheinlich / und hoffentlich nichts passieren.
aber was ist, wenn der speicher bereits mit daten gefüllt ist die nicht unbedingt von einer struktur her stammen.
ein x-beliebiger wert der dort steht müßte doch als pointer angesehen werde und die daten an der stelle im speicher entweder nicht existieren oder weitere x-beliebige daten enthalten. auf grund dieser könnte versucht werden einen speicher freizugeben der gar kein structurestring ist.

Wie verhält sich das vermutlich?
das kann man wohl nur schwer testen.

bisher aber schon mal viiielen dank. ich habe durch euch die möglichkeit (wie alle) jetzt endlich korrekt den speicher freizugeben.
wenn man jetzt noch sicher weiß wie es mit dem hier beschriebenen problem aussieht könnte ich versuchen das zu übernehmen.

bisher habe ich zwar auch die möglichkeite mit "eigenen strings die im memory stehen" angefangen einzubauen, aber das spätere umstellen (oder jetzige) ist ja kein großer aufwand.

[edit]
Ach ja, durch den ASM-Code, ist das dann nur unter Windows oder auch unter Linux zu gebrauchen?

gruß
thorsten