Der RESERVE-Befehl vergrößert oder verkleinert den BASIC-Arbeitsspeicher und reserviert nicht, wie der Name zuerst vermuten läßt, Speicher für das Anwenderprogramm. Für viele Anwendungen wird dieser Befehl sicher nicht benötigt, wenn man z.B. Gleichungen auflösen oder Kurven zeichnen will. Interessant wird es erst, wenn man Daten, welcher Art auch immer, speichern und verwalten will.
So empfiehlt es sich z.B. Maschinenprogramme in einen Speicherbereich abzulegen. Würde man das Programm einem String anvertrauen,
und
Will man größere Datenmengen verwalten, die viele Strings enthalten, sollte man sich, falls noch nicht getan, mit der Stringverwaltung des GFA BASIC vertraut machen:
Für jeden String, auch in Arrays, legt das BASIC einen String-Descriptor an. Dieser ist 6 Bytes lang und besteht
und
Nach dem eigentlichen String folgen
und
Die eventuelle Lücke zwischen dem Stringende und dem Backtrailer sorgt dafür, daß der Backtrailer immer an einer geraden Adresse steht. Dies ist notwendig, da auf Words und Longwords nur an geraden Adressen zugegriffen werden darf. Versucht man's trotzdem, so wird man mit einem erheiternden Address-Error, also 3 Bomben, belohnt. Der Backtrailer soll laut Handbuch eine wesentliche Beschleunigung der Garbage-Collection (=Müllsammlung =Beseitigung alter Strings) bewirken. Zückt man den Taschenrechner (Schande) und rechnet alles zusammen, benötigt ein Leerstring bereits 2*4+2=10 (!) Bytes. Hängt man ein oder zwei Zeichen dran, werden’s gleich zwölf!
Trägt sich jemand mit dem Gedanken, eine Datenbank für den Hausgebrauch zu schreiben, die z.B. 1000 Datensätze à 10 Datenfelder, also Strings, verwalten soll, werden gleich 105=100000 (einhunderttausend) Bytes für die Stringverwaltung verbraten. Wer für diesen Speicher eine bessere Verwendung hat, sollte die Datenverwaltung selbst in die Hand nehmen. Hierfür bieten sich durch RESERVE geschaffene Speicherfreiräume an.
Die Syntax dieses Befehls lautet folgendermaßen: RESERVE n.
n ist hierbei die Anzahl der Bytes, die das BASIC für sich selbst reservieren soll. Ein Fehler wird gemeldet, wenn man dem BASIC großzügigerweise mehr Speicher zu Verfügung stellen will, als im Rechnersystem überhaupt noch vorhanden ist.
Bei der Reservierung sollte man sich auch überlegen, wieviel Arbeitsspeicher das BASIC später zur Ausführung des Programms noch benötigen wird. Weiterhin sollte man beachten, daß die Größe des Arbeitsspeichers nur in Schritten von 256 Bytes verändert wird. Das bedeutet, daß FRE(0) nach der Befehlsausführung um max. 255 zu groß sein wird. Das hat zur Folge, daß der Speicher, den sich das eigene Programm reservieren wollte, um max. 255 zu klein sein kann, was unter Umständen schon zu Abstürzen führen kann.
Enthält die Variable nr% die Anzahl der für das BASIC zu reservierenden Bytes, sollte der Befehl folgendermaßen ausschauen:
RESERVE ((nr%\256)+1) *256
Enthält die Variable nr% die Anzahl der für das eigene Programm zu reservierenden Bytes, muß der Befehl modifiziert werden:
RESERVE FRE(0)-((nr%\256)+1)*256
Die Systemvariable HIMEM zeigt nach der Ausführung auf die neue Obergrenze des BASIC-Arbeitsspeichers.
In den geschaffenen Freiraum sollte man jetzt allerdings noch keine Daten ablegen, da sich jetzt auch noch andere Programme an dem Speicher gütlich tun können. Der reservierte Speicher muß zuerst geschützt werden. Dies geschieht mit Hilfe der GEMDOS-Funktion MALLOC. Beim Aufruf muß die Anzahl der zu schützenden Bytes übergeben werden. Der Aufruf sieht also folgendermaßen aus:
malloc adr%= GEMDOS (&48,L:nr%)
Die Variable mallocadr% enthält nach dem Aufruf entweder eine Fehlermeldung (adr = 0), oder sie zeigt auf den geschützten Bereich. Dieser hat die Größe von nr% Bytes und liegt für gewöhnlich direkt über HIMEM.
Nach diesen Vorbereitungen kann man die eigenen Daten unbesorgt im Speicher ablegen. Zur Verwaltung stehen ja eine Menge Befehle zur Verfügung, als da sind xPOKE, xPEEK. BMOVE, BLOAD, BSAVE, BGET und BPUT.
Vor Programmende, auch bei Programmunterbrechungen mittels SHIFT-ALTERNATE-CONTROL, sollte der geschützte Speicher wieder freigegeben und HIMEM wieder auf den alten Wert (vor RESERVE) gebracht werden. Das Entschützen geschieht mittels der GEMDOS-Funktion MFREE, beim Aufruf muß die Adresse übergeben werden, die man beim MALLOC-Aufruf als Rückgabeparameter erhalten hat:
VOID GEMDOS(&49,L:malloc adr%)
Um HIMEM auf den alten Wert zu bringen, wird wieder der RESERVE-Befehl verwendet:
RESERVE FRE(0)+((nr%\256)+1)*256
Im Demoprogramm befinden sich zwei Routinen, die selbstverständlich auch in eigene Programme eingebunden werden können:
PROCEDURE reserve_memory(nr%,adr1%,adr2%)
Diese Routine reserviert die in nr% übergebene Anzahl an Bytes. Der Aufruf erfolgt z.B. so:
GOSUB reserve_memory(1024,wrkadr%,*flg!)
wrkadr% zeigt nach dem Aufruf auf den Speicherbereich. Ist ein Fehler aufgetreten, so ist
flag!=TRUE
und
wrkadr%=0.
PROCEDURE release_memory(#nr%,adr1%)
Diese Routine gibt die in nr% übergebene Anzahl Bytes ab der in adr1% übergebenen Adresse frei. Der zum obigen Beispiel korrespondierende Aufruf erfolgt z.B. so :
GOSUB release_memory(1024,wrkadr%)
Wer unter GFA-BASIC GEM-Programme erstellt, sollte beim Programmabbruch darauf achten, daß von RSC-Files belegter Speicherplatz mittels der AES-Funktion RSRC_FREE() wieder freigegeben wird. Ansonsten erhält man beim soundsovielten Programmstart auf einmal einen Fehler bei RSRC_LOAD(), den man eigentlich auch abfangen sollte. Weiters müssen alle Fenster mittels WIND_CLOSE() geschlossen und durch WIND_DELETE gelöscht werden, sonst liegen nach mehreren Programmstarts
und
Am besten schreibt man eine Routine, die alle diese Aufgaben erledigt und bei Bedarf vom Interpreter durch ON ERROR GOSUB und ON BREAK GOSUB angesprungen wird.
' *******************************
' * DEMO-PROGRAMM ZUR ANWENDUNG *
' * DES RESERVE-BEFEHLS *
' * *
' * (c)1988 by Michael Marte *
' *******************************
'
Print "Freier BASIC-Arbeitsspeicher : ";Fre(0);" Bytes"
Print "Obergrenze des Arbeitsspeichers bei ";Himem
Print
Print "Wieviele Bytes sollen reserviert werden ?"
Input "",Nr%
Print
Gosub Reserve_memory(Nr%,*Wrkadr%,*Flg!)
If Flg!
Print "SPEICHERRESERVIERUNG : ";Nr%;" Bytes"
Print "Freier BASIC-Arbeitsspeicher : ";Fre(0);" Bytes"
Print "Obergrenze des BASIC-Arbeitsspeichers bei ";Himem
Print "Startadresse des reservierten Bereichs bei";Wrkadr%
Gosub Release_memory(Nr%,Wrkadr%)
Print
Print "SPEICHERFREIGABE : ";Nr%;" Bytes"
Print "Freier BASIC-Arbeitsspeicher : ";Fre(0);" Bytes"
Print "Obergrenze des BASIC-Arbeitsspeichers bei ";Himem
Else
Print "Fehler beim Reservieren."
Endif
'
Procedure Reserve_memory(Nr%,Adr1%,Adr2%)
Local Mallocfree%,Mallocadr%
*Adr1%=0 !Adresse=0
*Adr2%=True !kein Fehler
Nr%=((Nr%\256)+1)*256 !Reservierung erfolgt in 256-Byte Schritten
If Fre(0)<Nr% !Wenn (freier Speicher <Anzahl Bytes)
*Adr2%=False !dann Fehler
Else !sonst
Reserve Fre(0)-Nr% !BASIC-Speicher verkleinern
Mallocfree%=Gemdos(&H48,L:-1) !mallocfree%=freier Systemspeicher
If Mallocfree%<Nr% !Wenn (freier Systemspeicher<Anzahl Bytes)
*Adr2%«False !dann Fehler (irgendwas schiefgegangen)
Reserve Fre(0)+Nr% !BASIC-Speicher wieder vergrößern
Else !sonst
Mallocadr%=Gemdos(&H48,L:Nr%) !mallocadr%^Speicherblock
If Mallocadr%=0 !Wenn (mallocadr%=0)
*Adr2%=False !dann Fehler
Reserve Fre(0)+Nr !BASIC-Speicher wieder vergrößern
Else !sonst hat's geklappt
*Adr1%=Mallocadr% !kein Fehler : *adr1%^Speicherblock
Endif
Endif
Endif
Return
Procedure Release_memory(Nr%,Adr1%)
Nr%=((Nr%\256)+1)*256 !Reservierung erfolgt in 256-Byte Schritten
Void Gemdos(&H49,L:Adr1%) !MFREE, Speicher freigeben
Reserve Fre(0)+Nr% !BASIC-Speicher wieder vergrößern