AllocateMemory() zu klein » Warum geht das hier?

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

OK. Das mache ich ja in meinem Code. Anfangs allokiere ich 500 Byte (oder so) als Puffer. Die 4 Byte im Beispielcode habe ich genommen, falls noch ne NULL angehängt wird.

Ich hole immer 1000 Byte ab, sollte der freie Platz weniger als 500 Byte sein, erweitere ich den SPeicher um 1000 weitere Bytes.

Oder meinst du, ich soll, wenn ich allokiere, gleich genug SPeicherplatz für 3 oder 4 Häppchen allokieren?

Meinst du, das wäre performancemäßiger besser? Der folgende Code müsste eigentlich immer 5 Häppchen auf einmal holen, bevor er den Speicher neu allokiert:

Code: Alles auswählen

Define *buffer=AllocateMemory(5500) 
Repeat 
   If MemorySize(*buffer)-MemoryStringLength(*buffer) < 500
      Define *neu_buffer=ReAllocateMemory(*buffer, MemorySize(*buffer)+5000) 
      If *neu_buffer 
         *buffer=*neu_buffer 
      Else 
         Break 
      EndIf 
   EndIf 
Until ReceiveNetworkData(ConnectionID, *buffer, 1000) <> 1000
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

AND51 hat geschrieben: Oder meinst du, ich soll, wenn ich allokiere, gleich genug SPeicherplatz für 3 oder 4 Häppchen allokieren?
Ja. So wird eben nur bei jedem 3 oder 4 Durchlauf neuer Speicher
angefordert. Bei 1000 Bytes wuerde ich so mit dem etwa 8 fachem
Speicher anfangen.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Stimmt. 8 KB oder meinethalben auch 100 KB sind ja wie ein kleiner Pups. Tut nicht weh und ist performancemäßiger sehr viel besser.
Außerdem will ich ja den SPeicher freigeben, sobal er senen Zweck erfüllt hat (z. B. sofort nachdem eine empfangene Datei auf die Festplatte geschrieben wurde). Von daher würde ich diese Arbeitsweise schon als speicherplatzschonend bezeichnen.

Ich muss dann ja nur den Summand erhöhen, sodass bei Knappheit nicht um nur 1000 Byte , sondern 1024*100 Byte erhöht wird. Eine aufwändige Änderung es Codes ist also gar nicht nötig.

Nur, um mal alle Möglichkeiten ausgeschöpft und euch gefragt zu haben: Gibt es denn noch andere Methoden/Funktionen? Wie macht ihr das denn oder wie habt ihr das bereits realisiert oder wie würdet ihr das machen?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Du solltest noch den available Memory checken, nicht das Du reallocatest und
reallocates, jenseits jeder Möglichkeit :mrgreen:
Wenn Du das ergebnis nur als Datei benötigst, kannste es auch speichern
und ohne reallocieren immer denselben speicher nutzen.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

> Wenn Du das ergebnis nur als Datei benötigst, kannste es auch speichern und ohne reallocieren immer denselben speicher nutzen.
Das ist richtig. War ein nicht ganz passendes Beispiel. Aber ich denke meist immer schon weiter. Ich stelle mir eben ein Szenario vor, in dem ich einen HTTP Server programmiere, welches eben einen Upload unbekannter Größe entgegennehmen muss um... diese dann an einen Proxy/Gateway weiterzugeben oder sonstirgendwas. Muss ich halt situationsbedingt coden.

> nicht das Du reallocatest und reallocates, jenseits jeder Möglichkeit
Ich prüfe ja, ob das Reallokieren erfolgt oder fehlschlägt. Im Falle eines Fehlschlags muss ich mir nur noch überlegen was ich jeweils immer tun muss: Abbrechen oder mit den "halben" Daten weiterarbeiten.

> Du solltest noch den available Memory checken
Wie mache ich das denn? Mir fällt nur der Befehl ein, um zu ermitteln, wie viel Speicher der RAM der Grafikkarte hat. Oder meinst du ich soll den physikalischen RAM mit Hilfe einer API Funktion ermitteln?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

AND51 hat geschrieben: > Du solltest noch den available Memory checken
Wie mache ich das denn? Mir fällt nur der Befehl ein, um zu ermitteln, wie viel Speicher der RAM der Grafikkarte hat. Oder meinst du ich soll den physikalischen RAM mit Hilfe einer API Funktion ermitteln?
Wenn interessiert der GraKa Speicher, der ist schnurz (4 MB sollten reichen :mrgreen: )
Nein, mehr als die hälfte des verfügbaren Speichers würde ich ungerne
benutzen.

Code: Alles auswählen

; Structure MEMORYSTATUS
;   dwLength.l
;   dwMemoryLoad.l
;   dwTotalPhys.l
;   dwAvailPhys.l
;   dwTotalPageFile.l
;   dwAvailPageFile.l
;   dwTotalVirtual.l
;   dwAvailVirtual.l
; EndStructure

Define.MEMORYSTATUS MyMem

GlobalMemoryStatus_(@MyMem)
Debug MyMem\dwAvailPhys
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Zaphod
Beiträge: 2875
Registriert: 29.08.2004 00:40

Beitrag von Zaphod »

Meine Vermutung:
Windows verteilt Freispeicher in Form von vielfachen einer minimalen Blockgröße (gilt nicht für Variablen!). Ich weiß nichtmehr genau wie groß ein Block minimal ist, aber ich glaube es waren 4kb.

Ich vermute das PureBasic selbst nicht nachprüft, ob du einen allozierten Bereich zum überlaufen bringst. Wenn du den tatsächlich allozierten bereich überläufst, wird Windows aber freundlich danke sagen.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Nur um sicherzugehen: Mit "überlaufen" meinst du, mehr hineinzupoken als man vorher reserviert hat?

BTW "reservieren". Reserverien heißt doch nur, das man schon im Voraus Speicher bestellt. Aber wer sagt denn, das man nicht auch Speicher "direkt vor Ort" kaufen kann? Mit anderen Worten:
PokeS(Random()) könnte glücken, erwische ich zufällig einen freien Speicherbereich.

Oder: Ich reserviere 4 Tickets bei der Bahn, muss jedoch noch eines vor Ort kaufen, weil in letzter Minute noch einer mitfahren will. Da es genug freie Kapazitäten gibt, wieso soll das nicht gehen? So auch bei AllocateMemory(): Ich reserviere 4 Byte, schreibe aber 5 rein. Da auf heuteigen PCs immer genug freie Kapazitäten vorhanden sind, geht das auch.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
nco2k
Beiträge: 892
Registriert: 08.09.2004 23:13

Beitrag von nco2k »

ts-soft hat geschrieben:
AND51 hat geschrieben: > Du solltest noch den available Memory checken
Wie mache ich das denn? Mir fällt nur der Befehl ein, um zu ermitteln, wie viel Speicher der RAM der Grafikkarte hat. Oder meinst du ich soll den physikalischen RAM mit Hilfe einer API Funktion ermitteln?
Wenn interessiert der GraKa Speicher, der ist schnurz (4 MB sollten reichen :mrgreen: )
Nein, mehr als die hälfte des verfügbaren Speichers würde ich ungerne
benutzen.

Code: Alles auswählen

; Structure MEMORYSTATUS
;   dwLength.l
;   dwMemoryLoad.l
;   dwTotalPhys.l
;   dwAvailPhys.l
;   dwTotalPageFile.l
;   dwAvailPageFile.l
;   dwTotalVirtual.l
;   dwAvailVirtual.l
; EndStructure

Define.MEMORYSTATUS MyMem

GlobalMemoryStatus_(@MyMem)
Debug MyMem\dwAvailPhys
und damit es auch korrekt funktioniert auf systemen mit mehr als 4gb ram:

Code: Alles auswählen

Procedure.q GetFreeMemory()
  Library = OpenLibrary(#PB_Any, "kernel32.dll")
  If Library
    If OSVersion() >= #PB_OS_Windows_2000
      memex.MEMORYSTATUSEX
      memex\dwLength = SizeOf(MEMORYSTATUSEX)
      *Function = GetFunction(Library, "GlobalMemoryStatusEx")
      If *Function
        CallFunctionFast(*Function, @memex)
        Result.q = memex\ullAvailPhys
      EndIf
    Else
      mem.MEMORYSTATUS
      mem\dwLength = SizeOf(MEMORYSTATUS)
      *Function = GetFunction(Library, "GlobalMemoryStatus")
      If *Function
        CallFunctionFast(*Function, @mem)
        Result = mem\dwAvailPhys
      EndIf
    EndIf
    CloseLibrary(Library)
  EndIf
  ProcedureReturn Result
EndProcedure
Debug "Free Memory: "+Str(GetFreeMemory() / 1048576)+" MB"
edit: hab den code etwas abgeändert, da das direkte verknüpfen zu GlobalMemoryStatusEx_() unter win9x probleme bereiten wird. deswegen mache ich das ganze nun über OpenLibrary(), also nicht wundern. :wink:

c ya,
nco2k
~|__/
..o.o.. <--- This is Einkaufswagen. Copy Einkaufswagen into your signature to help him on his way to world domination.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

AND51 hat geschrieben:AllocateMemory(): Ich reserviere 4 Byte, schreibe aber 5 rein. Da auf heuteigen PCs immer genug freie Kapazitäten vorhanden sind, geht das auch.
:lol:
Ein Programmierer verwendet die meiste Zeit darauf, sein Programm
Sicher und Fehlerfrei zu machen. Von einem Programmierer kann obiger Satz
also nicht stammen :mrgreen:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten