RESERVE

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,

  1. müßte es relokatibel (im Speicher frei verschiebbar) sein

und

  1. man müßte die Aufrufadresse vor jedem Aufruf mittels der Funktion VARPTR() bestimmen, da der Interpreter nach meiner Erfahrung die Strings bei div. Stringoperationen und bei der Garbage-Collection fröhlich im Speicher umherschiebt.

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:

String-Verwaltung des GFA-BASIC

Für jeden String, auch in Arrays, legt das BASIC einen String-Descriptor an. Dieser ist 6 Bytes lang und besteht

  1. aus einem Longword (4 Bytes), welches einen Zeiger beinhaltet, der auf den eigentlichen String zeigt,

und

  1. aus einem Word (2 Bytes), welches die Länge des Strings beinhaltet (max. 32767 Bytes).

Nach dem eigentlichen String folgen

  1. ein Nullbyte, falls der String eine ungerade Länge hat,

und

  1. ein Longword, der sogenannte Backtrailer, der auf den String-Descriptor zeigt.

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.

Tücken des Reserve-Befehls

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.

Anwendung

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

Das Programm

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%)

Allgemeine Hinweise

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

  1. eine Menge Fenster auf dem Desktop herum, die aber nicht mehr benutzt werden können,

und

  1. wird bei WIND_CREATE() Fehler geben (abfangen!), weil das AES keine Fenster mehr zur Verfügung stellen kann.

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

Michael Martens
Aus: ST-Computer 02 / 1989, Seite 94

Links

Copyright-Bestimmungen: siehe Über diese Seite