Seite 1 von 1

Richtiges Nutzen von AllocateMemory()

Verfasst: 10.07.2019 23:57
von diceman
Hallo allerseits,
Ich habe mal wieder eine Noob-Frage ...
Und zwar habe ich in meiner ganzen Zeit mit PureBasic noch kein einziges Mal den Befehl "AllocateMemory()" benutzt ... ergo weiß ich auch gar nicht, was dieser überhaupt tut, und wie man ihn zweckmäßig nutzt, und ob er für meine Zwecke überhaupt relevant ist; ich sehe ihn aber andauernd in Beispiel-Codes im Forum und anderswo. Die F1-Hilfe ist mir bei meiner Frage keine große Hilfe, die ist sehr abstrakt und allgemein gehalten. Irgendwie wird Speicher reserviert, okay. Aber wie, warum, wozu? Und warum komme ich "trotzdem" klar, auch ohne den Befehl zu verwenden?
Ist das Speicher allokieren evtl. nur in Kombination mit "Peek" und "Poke" sinnvoll (beide noch nie verwendet) ... ? :|
Grafik-, Sound- und File-Operationen führe ich in meinen Applikationen dagegen am laufenden Band durch, ich nutze Structures und Listen, Pointer, "pass by reference" und "PB-Any". /:->
Aber irgendwie wurmt es mich schon, daß es da draußen ein weiteres Konzept gibt, daß ich ums Verrecken nicht verstehe, und was mir vielleicht dabei helfen könnte, noch effizienter und sauberer zu programmieren.
Vielen Dank!

Re: Richtiges Nutzen von AllocateMemory()

Verfasst: 11.07.2019 00:40
von NicTheQuick
Wie ist denn deine Erfahrung mit Pointern? Wozu nutzt du sie? Normalerweise nutzt man die häufig auf Speicherbereichen, die man mit AllocateMemory oder AllocateStructure alloziert hat.

Vielleicht ein einfaches Beispiel: Du kannst eine Datei öffnen, mit Lof() die Dateigröße bestimmen, dann mit AllocateMemory() entsprechend viel Speicher allozieren und dann mit ReadData() die gesamte Datei in diesen Speicherbereich laden. Dann hast du die gesamte Datei im RAM und kannst mit Peek, Poke oder mit Pointern in diesem Speicherbereich Daten lesen und ändern.
AllocateMemory() reserviert also entsprechend viel Speicher im RAM deines PCs, in den du beliebig schreiben und wieder lesen kannst.

Re: Richtiges Nutzen von AllocateMemory()

Verfasst: 11.07.2019 00:49
von Bisonte
AllocateMemory() reserviert einen Speicher für die eigene Nutzung.

Du hast "Pointer" ja schon genutzt, vermutlich sowas wie @MeineVariable oder @MeineListe().
Das ist im Grunde schon das gleiche. Allerdings ist das ganze flüchtig.

Wenn man z.B. einem Gadget mehr Daten mitgeben möchte, ohne eine List() oder Map() zu benutzen,
kann man das nur über einen reservierten Speicherbereich machen, da ansonsten der Speicher nach beenden
einer Prozedur z.B. nicht mehr existiert, bzw. keinen definierten Wert mehr besitzt.

Damit kann man dann per SetGadgetData(Gadget, *Speicher) dem Gadget jede Menge Daten "anhängen".
Am besten mit einer Struktur, damit das ganze bequemer zu füllen und auszulesen ist.

Beispiele :

Code: Alles auswählen

Structure myGadget
  Window.i
  Font.i
  Farbe.l
  Flag.l
EndStructure

*Speicher.myGadget = AllocateMemory(SizeOf(myGadget))
*Speicher\Farbe = #Red

SetGadgetData(Gadget, *Speicher)

*Speicher = GetGadgetData(Gadget)
Debug *Speicher\Farbe
Wobei mittlerweile das AllocateMemory() in Verbindung mit einer Struktur nicht mehr genommen wird, sondern
AllocateStructure(), da es gleich das InitializeStructure mitmacht (das auch Listen/Maps und Strings richtig initialisiert)
und nebenbei Schreibarbeit spart ;)

Re: Richtiges Nutzen von AllocateMemory()

Verfasst: 11.07.2019 17:32
von diceman
Ja vielen Dank, dann ist es doch schon etwas klarer geworden. :-)
In der Tat nutze ich *pointer primär in Zusammenhang mit Listen; z.B. um Elemente miteinander zu vergleichen, oder nach einem erneuten ForEach-Aufruf innerhalb einer ForEach-Schleife den ursprünglichen Zustand der ersten ForEach-Schleife wieder herzustellen, etc. Da muß man natürlich hin und wieder aufpassen, daß man mit ChangeCurrentElement nicht versucht, ein gerade gelöschtes Element wieder herzstellen, sonst gibt's Schläge vom Compiler.
Ich habe eine prägende Blitzbasic-Vergangenheit, daher gehören Strukturen und Listen für mich zwangsläufig zusammen, bzw. sobald ich eine Struktur deklariert habe, initialisiere ich sogleich eine zugehörige Liste um evtl. erstellte Elemente ordentlich verwalten zu können (hier schlägt PureBasic BlitzBasic um Längen, was Tools angeht, und der damit entstehende kreativer Spielraum).
Dann weiß ich jetzt zumindest, daß ich nichts falsch mache, bzw. es auch anders geht.
Und sollte ich tatsächlich mal tatsächlich in die Situation kommen sollte, daß ich eine komplette Datei in den Speicher laden muß, weiß ich, was ich dafür tun muß.

Re: Richtiges Nutzen von AllocateMemory()

Verfasst: 11.07.2019 18:12
von Sicro
Mit AllocateMemory() hast du die Möglichkeit, darauf zu reagieren, wenn der Speicher nicht reserviert werden konnte:

Code: Alles auswählen

#KiB = 1024
#MiB = #KiB * 1024
#GiB = #MiB * 1024
*memory = AllocateMemory(40*#GiB)
If *memory
  PokeB(*memory + 10, 22) ; Write test
  FreeMemory(*memory)
Else
  Debug "Fehler: Speicher konnte nicht reserviert werden!"
EndIf
Hier eine Variante ohne AllocateMemory():

Code: Alles auswählen

#KiB = 1024
#MiB = #KiB * 1024
#GiB = #MiB * 1024
; Wie bei AllocateMemory() reservieren wir 40 GigaByte RAM:
Dim memory.b(40*#GiB)
memory(10) = 22 ; Write test     <= Ganzes Programm stürzt sofort ab!

Re: Richtiges Nutzen von AllocateMemory()

Verfasst: 11.07.2019 18:46
von Imhotheb
Gibt es bei Dim einen Max-Wert?

Weil das hier:

Code: Alles auswählen

#KiB = 1024
#MiB = #KiB * 1024
#GiB = #MiB * 1024
*memory = AllocateMemory(40*#GiB)
If *memory
  Debug MemorySize(*memory)     ; 42949672960
  FreeMemory(*memory)
Else
  Debug "Fehler: Speicher konnte nicht reserviert werden!"
EndIf
korrekte 42949672960 ausgibt.

Dieser Code:

Code: Alles auswählen

#KiB = 1024
#MiB = #KiB * 1024
#GiB = #MiB * 1024
; Wie bei AllocateMemory() reservieren wir 40 GigaByte RAM:
Dim memory.b(40*#GiB)
Debug ArraySize(memory())     ; 0 ... sollte auch 42949672960 sein
aber nur 0.

Re: Richtiges Nutzen von AllocateMemory()

Verfasst: 12.07.2019 00:38
von TroaX
Für AllocateMemory gibt es viele Gründe. Grundsätzlich ist die Beschreibung in der Hilfe genau das, wie es auch zu beschreiben ist. Man reserviert einen Zusammenhängenden Speicherbereich. Dies ist aus verschiedenen Gründen nötig. Zum einen kann man in dem Speicher alles an Daten ablegen. Zum anderen kann man jedes erdenkliche Byte aus diesem Bereich abrufen oder ändern.

Es kommt immer auch darauf an, was man macht. Ich verwende es relativ häufig. Zum Beispiel beim Webserver, bei dem man nie weiß, wie groß die übertragenen Daten sind oder welchem Typ sie angehören. Oder allgemein Netzwerkgeschichten. Ich vermeide es auch gerne. Aber oftmals kommt man auch einfach nicht drum herum.

Re: Richtiges Nutzen von AllocateMemory()

Verfasst: 12.07.2019 09:14
von mk-soft
Da man mit Pointer sich auch schnell vertun kann, hier eine Erweiterung im Debuggermodus

Code: Alles auswählen

;-TOP
;
; Memory Debugging v0.5

CompilerIf #PB_Compiler_Debugger
  
  #MemoryStop = 1
  
  Global NewMap MemID()
  
  Procedure MyAllocateMemory(Size, Flags, Proc.s)
    Protected *mem
    *mem = AllocateMemory(Size, Flags)
    If *mem
      MemID(Hex(*mem)) = *mem
    Else
      CompilerIf #MemoryStop
        If MessageRequester("AllocateMemory", "Out Of Memory : " + #LF$ + "Proc: " + Proc, 
                            #PB_MessageRequester_YesNo | #PB_MessageRequester_Error) = #PB_MessageRequester_No
          End
        EndIf
      CompilerElse
        DebuggerWarning("FreeMemory: Out Of Memory : " + Proc)
      CompilerEndIf
      ProcedureReturn #False
    EndIf
    ProcedureReturn *mem
  EndProcedure
  
  Procedure MyFreeMemory(Memory, Proc.s)
    If FindMapElement(MemID(), Hex(Memory))
      FreeMemory(Memory)
      DeleteMapElement(MemID())
      ProcedureReturn #True
    Else
      CompilerIf #MemoryStop
        If MessageRequester("FreeMemory", "Memory not exists : " + #LF$ + "Proc: " + Proc, 
                            #PB_MessageRequester_YesNo | #PB_MessageRequester_Error) = #PB_MessageRequester_No
          End
        EndIf
      CompilerElse
        DebuggerWarning("FreeMemory: Memory not exists : " + Proc)
      CompilerEndIf
      ProcedureReturn #False
    EndIf
  EndProcedure
  
  Procedure MyMemorySize(Memory, Proc.s)
    If FindMapElement(MemID(), Hex(Memory))
      ProcedureReturn MemorySize(Memory)
    Else
      CompilerIf #MemoryStop
        If MessageRequester("MemorySize", "Memory not exists : " + #LF$ + "Proc: " + Proc, 
                            #PB_MessageRequester_YesNo | #PB_MessageRequester_Error) = #PB_MessageRequester_No
          End
        EndIf
      CompilerElse
        DebuggerWarning("MemorySize: Memory not exists : " + Proc)
      CompilerEndIf
      ProcedureReturn 0
    EndIf
  EndProcedure
  
  Macro AllocateMemory(Size, Flags=0)
    MyAllocateMemory(Size, Flags, #PB_Compiler_Module + "/" + #PB_Compiler_Procedure + "() - Line " + #PB_Compiler_Line)
  EndMacro
  
  Macro FreeMemory(Memory)
    MyFreeMemory(Memory, #PB_Compiler_Module + "/" + #PB_Compiler_Procedure + "() - Line " + #PB_Compiler_Line)
  EndMacro
  
  Macro MemorySize(Memory)
    MyMemorySize(Memory, #PB_Compiler_Module + "/" + #PB_Compiler_Procedure + "() - Line " + #PB_Compiler_Line)
  EndMacro
  
CompilerEndIf

;- test

Procedure Main()
  *mem1 = AllocateMemory(1024)
  ;*mem2 = AllocateMemory(2048)
  
  Debug "Size 1: " + MemorySize(*mem1)
  Debug "Size 2: " + MemorySize(*mem2)
  
  Debug "Free 1: " + FreeMemory(*mem1)
  Debug "Free 2: " + FreeMemory(*mem2)
EndProcedure : main()

Re: Richtiges Nutzen von AllocateMemory()

Verfasst: 12.07.2019 11:47
von diceman
Danke für deine Mühe, den Code gucke ich mir nachher mal an. :)
Habe jetzt, glaube ich, selbst ein Beispiel gefunden, wo AllocateMemory() relevant für mich werden könnte, und zwar wenn ich mit ReceiveHTTPFile eine Seite aus dem Netz ziehe um diese z.B. nach Keywords zu durchforsten, müßte ich Speicher reservieren, in denen ich die Website-Daten ablegen kann, bevor ich irgend etwas Sinnvolles mit dem File anstellen kann ...