Seite 1 von 2

MultiAllocateMemory

Verfasst: 18.10.2006 11:44
von NicTheQuick
Im Zuge meines Datenbankprojektes, bin ich zu folgendem kleinen
Ablenkungscode gekommen.

Praktisch ist der Code bei folgendem Problem: Wenn man mehrere Speicherblöcke gleichzeitig allokieren will und ein AllocateMemory()
fehltschlägt, dann bringen einem die schon zuvor allokierten Speicherblöcke
meist auch nichts mehr und man muss sie wieder freigeben.

Hier ist jetzt alles zusammengefasst.

Code: Alles auswählen

;info: MultiAllocateMemory

Procedure AllocateMemoryEx(*hnd.Long, Size.l, mode.l)
  Structure AllocMem
    *hnd.Long
    Size.l
  EndStructure
  Static NewList AllocMem.AllocMem(), Count.l, allocated.l
  
  Select mode
    Case 1
      If *hnd And Size
        If AddElement(AllocMem())
          *hnd\l = 0
          AllocMem()\hnd = *hnd
          AllocMem()\Size = Size
        EndIf
      EndIf
    
    Case 2
      SortStructuredList(AllocMem(), 1, SizeOf(AllocMem\Size), #PB_Sort_Long)
      ForEach AllocMem()
        AllocMem()\hnd\l = AllocateMemory(AllocMem()\Size)
        If AllocMem()\hnd\l : allocated + 1 : EndIf
        Count + 1
      Next
      
      If allocated = Count
        ClearList(AllocMem())
        ProcedureReturn #True
      Else
        ForEach AllocMem()
          If AllocMem()\hnd\l : FreeMemory(AllocMem()\hnd\l) : EndIf
        Next
        ClearList(AllocMem())
        ProcedureReturn #False
      EndIf
  EndSelect
EndProcedure

Macro AddMultiAllocateMemory(phnd, Size)
  AllocateMemoryEx(phnd, Size, 1)
EndMacro

Macro MultiAllocateMemory()
  AllocateMemoryEx(0, 0, 2)
EndMacro
Jetzt ein Beispiel, wie es kompliziert geht und wie es einfach geht. :)

KOMPLIZIERT

Code: Alles auswählen

a = AllocateMemory(100)
If a = 0 : End : EndIf
b = AllocateMemory(1000)
If b = 0 : FreeMemory(a) : End : EndIf
c = AllocateMemory(100000)
If c = 0 : FreeMemory(a) : FreeMemory(b) : End : EndIf
d = AllocateMemory(10000)
If d = 0 : FreeMemory(a) : FreeMemory(b) : FreeMemory(c) : End : EndIf
e = AllocateMemory(1000)
If e = 0 : FreeMemory(a) : FreeMemory(b) : FreeMemory(c) : FreeMemory(d) : End : EndIf

Debug "Es konnten alle Speicherblöcke allokiert werden:"
Debug a
Debug b
Debug c
Debug d
Debug e
EINFACH

Code: Alles auswählen

AddMultiAllocateMemory(@a, 100)
AddMultiAllocateMemory(@b, 1000)
AddMultiAllocateMemory(@c, 100000)
AddMultiAllocateMemory(@d, 10000)
AddMultiAllocateMemory(@e, 1000)
If MultiAllocateMemory()
  Debug "Es konnten alle Speicherblöcke allokiert werden:"
  Debug a
  Debug b
  Debug c
  Debug d
  Debug e
Else
  Debug "Mindestens ein Speicherblock konnte nicht allokiert werden."
EndIf
Vielleicht kann es ja der ein oder andere gebrauchen oder zumindest als
Anregung dafür sehen, dass man immer wieder alles freigeben und
Rückgabewerte kontrollieren sollte.

Re: MultiAllocateMemory

Verfasst: 18.10.2006 13:34
von Kaeru Gaman
NicTheQuick hat geschrieben:Praktisch ist der Code bei folgendem Problem: Wenn man mehrere Speicherblöcke gleichzeitig allokieren will und ein AllocateMemory()
fehltschlägt, dann bringen einem die schon zuvor allokierten Speicherblöcke
meist auch nichts mehr und man muss sie wieder freigeben.
:shock: ne, echt jetzt? und wie kann man das noch umgehen?
schafft es abhilfe, wenn man zuerst nen dummi in die mem schreibt,
bevor man versucht, die nächste zu allocieren?


[edit]
und ich seh grad, du bist in deinem code auch auf ein anderes problem gestoßen,
dass mir auch schon zu schaffen machte:
Shared NewList geht nicht!
...shared is im grunde sowieso ein witz, hat nix mit dem richtigen shared zu tun wie es sein sollte.

Verfasst: 18.10.2006 14:11
von NicTheQuick
Da steht kein Shared, sondern ein Static und das funktioniert.
Funktioniert natürlich nur mit PB 4.00!

Und wie meinst du das mit dem Dummy?

Verfasst: 18.10.2006 15:05
von Kaeru Gaman
> Da steht kein Shared, sondern ein Static und das funktioniert.

ich kann lesen. aber du verwendest ein MODE, damit du dieselbe Proc für 2 funktionen aufrufen kannst.
wenn Shared NewList funktionieren würde, könntest du das auf zwei procs aufteilen, die beide auf dieselbe LL zugreifen.

> Und wie meinst du das mit dem Dummy?

na, den soeben allocierten speicher belegen.

ich mein, es geht doch nich an, dass wenn ich irgendwann später in meinem prog etwas mem allociere,
und das fehlschlägt, dann sämtlicher zuvor allocierter mem im anus ist.
also muss es doch ne möglichkeit geben, eine aktion zwischendrin zu machen,
wie z.b. den eben allocierten mem mit nem dummy zu belegen,
was dafür sorgt, dass der mem erhalten bleibt, auf wenns nächste alloc fehlschlägt.

Verfasst: 18.10.2006 15:31
von #NULL
mit
"..und ein AllocateMemory() fehltschlägt, dann bringen einem die schon zuvor allokierten Speicherblöcke meist auch nichts mehr und man muss sie wieder freigeben. "
meint NTQ doch nur, dass man den bereits alloz. speicher nicht mehr braucht, weil man die geplanten arbeiten ja nicht durchführen kann.

Verfasst: 18.10.2006 15:32
von ts-soft
>> was dafür sorgt, dass der mem erhalten bleibt, auf wenns nächste alloc fehlschlägt.
Vielleicht das erste Posting nochmals lesen :wink:
Es geht darum, das, sobald ein Allokieren schief geht, automatisch aller
Speicher, in diesem Zusammenhang, freigegeben wird, da er meist nicht
mehr gebraucht wird.

Was nützt mir der Mem, wo ich eine Datei einlese, wenn ich den Mem zum
Verschlüsseln nicht allokieren kann? Also sollen alle autom. freigegeben
werden, weil ich die Datei wohl nicht mehr einlese.

Hoffentlich halbwegs verständlich /:->

Gruß
Thomas

Verfasst: 18.10.2006 15:58
von NicTheQuick
@Kaeru:
Jetzt habe ich dich - denke ich - verstanden. :!:

Zuerst zu dem Shared:
Auch wenn Shared funktionieren würde, wollte ich es nicht benutzen,
weil es dann immer noch im dem aufrufenden Programm eine LinkedList mit
dem selben Namen geben könnte. Mit Static ist die LinkedList aber
schön gekapselt. Leider funktioniert so das ganze nicht mehr in mehreren
Threads gleichzeitig. Aber das fand ich jetzt eher nebensächlich.

Jetzt wegen dem Dummy:
Ich hab immer noch keine Ahnung wie und warum du Speicher belegen willst,
damit er nicht mehr freigegeben wird. Denn er soll doch wieder freigegeben
werden, wenn ein Speicherblock nicht allokiert werden kann. Außerdem
wird, wenn du einmal MultiAllocateMemory() aufrufst, wieder die komplette
LinkedList gelöscht, wodurch irgendwann später in deinem Programm auch
nicht ungewollt wieder irgendwo Speicher von vorher freigeben wird.

Ansonsten denke ich, haben ts-soft und #Null gut erklärt, was du noch
wissen wolltest. :allright:

Verfasst: 18.10.2006 16:29
von Kaeru Gaman
nicht ganz.

wenn ich in einem bestimmten zusammenhang mehrfach speicher allociere, ist mir das einleuchtend.
wie ts sagte:
> Was nützt mir der Mem, wo ich eine Datei einlese, wenn ich den Mem zum
> Verschlüsseln nicht allokieren kann?

meine überlegung geht dahingehend, ob es denn passieren kann,
dass ich in einem projekt an verschiedensten stellen speicher allocieren kann,
und es wenn irgendwann einmal der vorgang fehlschlägt, denn das ganze programm gescheitert ist.

vielleicht hab ich ja nen editor, in dem ich irgendwas erstellen will,
und für die nächste operation ist nicht mehr genügend speicher vorhanden,
ich bekomme ne fehlermeldung, kann diese operation also nicht mehr ausführen,
möchte aber vielleicht trotzdem meine bisherige arbeit auf platte speichern.

wenn jetzt bei dem letzten fehler sämtlicher zuvor vom programm
allocierter speicher automatisch freigegeben wird, ist die ganze arbeit für die katz gewesen,
und das kann doch nicht sinn der sache sein, so kann man doch nicht programmieren.

wenn ich in irfanview etwas total verrücktes machen will
(ein 40000x30000 bild nochmal auf 1000% vergrößern)
dann meckert er mir den fehlenden speicher an,
aber das alte bild ist noch da.

Verfasst: 18.10.2006 17:22
von NicTheQuick
Na dann bist du ja auch selbst Schuld, weil du es nicht gescheit programmiert
hast. <)

Dein Bild ist nicht weg... blubb .... Blablabla... Ach, ich mach einfach ein
Beispiel... Moment...

So... Müsste selbsterklärend sein. Und wo werden da jetzt die Speicherblöcke
von am Anfang freigegeben? Ist dir eigentlich schon das ClearList() in
meiner Procedure aufgefallen? ;)

Code: Alles auswählen

AddMultiAllocateMemory(@Mem1, 10000)
AddMultiAllocateMemory(@Mem2, 100000)

If MultiAllocateMemory()
  Debug "Speicher wurde allokiert"
  Debug Mem1
  Debug Mem2
Else
  Debug "?? So wenig RAM ??"
EndIf

Debug ""
AddMultiAllocateMemory(@Mem3, 1000000)
AddMultiAllocateMemory(@Mem4, 1024 * 1024 * 1024)

If MultiAllocateMemory()
  Debug "Speicher wurd allokiert !!"
  Debug Mem3
  Debug Mem4
Else
  Debug "Speicher wurde nicht allokiert, warum nur?"
  Debug "aber Mem1 und Mem2 sind noch da:"
  Debug MemorySize(Mem1)
  Debug MemorySize(Mem2)
EndIf
Wenn du jetzt immer noch nicht zufrieden bist, dann weiß ich auch nicht
weiter. Vielleicht kann es ja jemand anders besser erklären.

Verfasst: 18.10.2006 18:02
von HeX0R
Wenn ich mehrere Blöcke brauche mach ich es in der Regel so:

Code: Alles auswählen

*A = AllocateMemory(10 * 1024)
If *A
	*B = *A + 1024
	*C = *B + 1024
	*D = *C + 1024
	*E = *D + 1024
EndIf
Also einen Block, der gleich für alle meine kleinen Blöcke ausreicht und verschiedene Pointer, um drauf zuzugreifen.
So sehe ich auch gleich bei einem einzigen AllocateMemory(), ob genug Speicher da ist.
(Und brauch auch nur ein FreeMemory() aufrufen).