Seite 2 von 3

Verfasst: 06.04.2007 21:33
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

Verfasst: 06.04.2007 22:15
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.

Verfasst: 06.04.2007 22:26
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?

Verfasst: 06.04.2007 22:39
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.

Verfasst: 07.04.2007 01:24
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?

Verfasst: 07.04.2007 01:47
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

Verfasst: 07.04.2007 03:32
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.

Verfasst: 07.04.2007 13:27
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.

Verfasst: 07.04.2007 13:54
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

Verfasst: 07.04.2007 17:07
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: