Segment
Volume Number: 2
Issue Number: 11
Column Tag: Basic School
Using the Segment Manager from Basic 
By Dave Kelly, MacTutor Editorial Board
This month we'll discuss Macintosh memory management (part 2, part 1 was
discussed back in the June 1985 MacTutor). While the information back in June 1985
is still valid, there are some other (new?) considerations that I haven't mentioned yet.
If you have the June '85 MacTutor go back and review that information as it will be
useful here as we talk about it some more. It would also be helpful to read Inside
Macintosh Vol. I chapter 3 on Memory Management and Vol II chapter 2 on the Segment
Loader.
Now that we have as much memory available as we ever dreamed we might have
(remember when it was so great to have 16K RAM?), we need to talk about the best
ways to make use of it. In review, please recall that the key to memory management in
MS Basic is the CLEAR statement. Even on a Macintosh Plus you should use CLEAR to
make the best use of the available memory. The following procedure will help you to
quickly set up the memory configuration:
1. Load your program and before running it type PRINT FRE(0) in the command
window to determine the amount of memory used by your program listing. Record
this number for later use.
2. Run the program. The intent here is to determine the amount of memory that
your variables need. For some programs you may not be able to run enough of the
program to declare all of the variables. In that case you may have to do some
rough guessing here. Either after running your program or sometime during the
program (this may be more convenient) you should print FRE(0) again. The
difference between this number and the number you recorded in step 1 above is
the amount of memory allocated to the data segment that is used for your
variables. (FRE(-1) returns the number of bytes not used in the heap; FRE(-2)
returns the number of bytes in the stack that have not been used; you may use
these if it will help you).
3. Now it's time to guess. Try to decide if the program will ever need more memory
than this in the future. If you need to increase the program size later or allocate
more variables you will need to allow some space for this. If you are not sure you
may want to just add 20% or so more memory to the length of the program.
Whatever you decide here will be your data segment memory.
4. Now, if your program uses any Macintosh resources you will need to figure out
how much of the heap to use. If you have extra memory like on the Mac plus it
never hurts to have extra heap space. In fact, the heap may be more heavily used
than the data segment depending on how many controls, or windows, etc. you may
be using. Keep in mind also that if any desk accessories are opened they will need
some heap space of their own. By printing FRE(-2) it will show the heap
memory allocation. If you print FRE(-2) before running the program you will
know the amount of heap available to the program. After the program is run and
resources are loaded, the amount of heap will decrease. You need to know the
difference between the FRE(-2) before and after running the program. Record
this number.
5. Now you need to calculate the stack-size to use in the CLEAR statement. Many
times it is not even necessary to change the data segment (leave it as large as the
memory you have left). The number to use for the stack-size is calculated by
stack-size = Total Ram - (data-segment-size + heap-size).
Fig. 1 Output of our Segment Program
Now how do you know when you need to adjust the memory allocation? Ans:
Anytime that you notice an unusual amount of disk activity, e specially just before
displaying controls (edit fields, buttons, menus, windows etc.). It doesn't matter if you
have a Mac Plus or not, if you don't adjust your memory properly, then the memory
will not be used efficiently. In order to remain compatible with the 512K & 128K Mac,
the heap and stack default sizes are the same on the Mac plus. This may explain why so
many Mac programs need to read the disk so often even though you may think you have a
lot of memory (1Meg really is plenty for Basic!!). Good memory management planning
can improve your program tremendously. Another thing to keep in mind is that once
the CLEAR statement has been used to change the memory allocation it will remain that
way for the next program that you load into memory. A second CLEAR statement will not
reallocate the memory properly. It is best to quit to the finder and start all over unless
the new program uses the same memory configuration.
So much for MS Basic memory management. The comments above in addition to
those in the June '85 MacTutor should give you all you need to handle most of your
memory management. Memory management in other languages is handled through use of
the Segment Loader. Access to the Segment Loader is not provided in MS Basic. ZBasic
provides the SEGMENT and SEGMENT RETURN statements which use the Segment Loader.
We'll talk about those in a moment. First a few words about the Segment Loader. The
Segment Loader allows you to divide up the code of your application into several parts.
When the Finder starts up your application the Segment Loader is called to load in the
main segment of your program. Other segments are loaded in automatically as needed.
After a segment is no longer needed, your application can call the segment loader to
make the segment purgable. This way if you have only a small amount of memory
available you may still run a large program. The maximum size of a segment is 32K.
Any code that is not used often may be in a separate segment so that it may be swapped in
whenever it is needed. Another function of the Segment Loader is in supplying
information from the Finder.
Your ZBasic code will be compiled into code segments ( resources of type 'CODE')
automatically, no matter if you use the SEGMENT statements or not. When the code
reaches a length of about 28K the segment will end and the next segment will be loaded.
The SEGMENT RETURN statement marks the end of the CODE segment and returns to the
calling routine (cannot be called from the same segment). You should arrange your
application such that a segment consists of a subroutine. The routines you decide to
separate into segments preferably should be routines which are only used occasionally
(example: print routines).
The following example program demonstrates how to "segmentize" your
programs. However, because the segments in the example are small (less than 100
bytes), the segment memory swapping is virtually non-existent on a Macintosh plus
(and probably all the other size Macs too!). If you really want to try this out, you'll
have to write some larger CODE segments and run on a smaller Mac. You can check the
segment sizes by choosing the COMPILE option of the ZBasic command menu. The sizes
of the segments will be displayed. The remaining memory can be found with the
MEM(-1) function. MEM(-1) returns the maximum amount of available memory for
the program and variables.
Another part of the Segment Loader is supported by ZBasic with the FINDERINFO
function. The FINDERINFO function returns information to your application which
tells the application how the application was selected from the Finder. The function
returns variables with the number of files selected, the name of the files and volume
number, and a message variable indicating if the file should be loaded or printed. This
way the files may be printed (or whatever) without going through the full set of
initialization routines that your application may have. If no files have been selected
then your application should open a new untitled document and continue from there.
The syntax is: message%= FINDERINFO (count%, var$[(n)], type%[(n)],
volume%[(n)]). The message variable is the result of the FINDERINFO function. If the
result is equal to zero then the file should be loaded otherwise the file should be printed.
The Count% variable returns the number of files . The variable var$(n) is a string
variable or string array with the names of the files which have been selected. The file
type of the selected files is stored in a long integer word which must be converted to a
string by using the MKI$ statement. The volume% variable is the the disk volume
where the file is located.
To get the FINDERINFO function to work, first you must compile your program as
an application. There are two or three statements that must be used properly in order
to compile the program so that the function will work. First type CREATOR "ffff
where "ffff" is the creator name which will be given to the application. The other
statement that must match this one is the DEFOPEN "ffffcccc" statement which sets up
the file type ("ffff") and the file creator ("cccc") for the data files created by your
application. In the demo program the creator is "DAVE" and the file type is "DATA".
The DEFOPEN statement is used in the application program when opening up new data
files. Now that the creator is the same for the application as for the data, we need to set
the bundle bit with the BUNDLE 1 statement. Type BUNDLE 1 in the command window.
Now it is time to compile the program into an application. Select RUN* from the menus
to create the application. New data files which are created with the application will
now be linked to each other. Selecting one or more data files while in the Finder and
selecting PRINT or OPEN will open the application which the data files belong and send
info to the application via the FINDERINFO statement. To see the results of this
function, you may want to run the demo and create a few sample data files and see what
happens when they are selected for printing or to be opened.
If you have problems getting the FINDERINFO information, be sure that you set
the creator and bundle bit before compiling the application. You should also be sure to
define all the variables in the function before calling it. More information on the
Segment Loader is available in Vol 2, Chap. 2 of Inside Macintosh (The Segment Loader
chapter).
WINDOW OFF
REM Segment Loader Example ZBasic 3.02
REM ©MacTutor 1986
REM by Dave Kelly
DIM 31 Name$(5),Vol%(5),Type&(5),Mes$(1)
REM up to 5 files can be selected.
DEFSTR LONG
Count%=2
Message%=FINDERINFO(Count%, Name$(0), Type&(0), Vol%(0))
X&=MEM(-1)
WINDOW 1,"Segment Sample",(50,100)-(475,300),257
IF Count%<>0 THEN GOSUB "DisplayFINDERINFO
MENU 1,0,1,"File
MENU 1,1,1,"Create Data File
MENU 1,2,1,"Quit
MENU 2,0,1,"Segments
MENU 2,1,1,"Main Segment
MENU 2,2,1,"1st Segment
MENU 2,3,1,"2nd Segment
MENU 2,4,1,"3rd Segment
MENU 2,5,1,"Check memory available and unload unused segments
ON MENU GOSUB "Menu event
MENU ON
"Loop":
GOTO "Loop
"Menu event":
Menunumber=MENU(0)
Menuitem=MENU(1)
MENU
MENU OFF
ON Menunumber GOSUB "Filemenu","Segmenu
MENU ON
RETURN
"Filemenu":
IF Menuitem=1 THEN "Openfile
IF Menuitem<>2 THEN RETURN
MENU RESET
END
"Openfile":
DEF OPEN "DATADAVE
Filename$=FILES$(0,"Create new file as ..." ,"Segment DATA")
IF Filename$="" THEN RETURN
OPEN O,#1,Filename$
PRINT "New file named ";Filename$;" has been created.":PRINT
PRINT "Quit the program and click on "; Filename$; " to see how
the
PRINT "FINDERINFO function works. Select PRINT or OPEN from the
Finder.
PRINT "The FINDERINFO function will indicate what has been s
selected.
PRINT "You may want to create multiple data files and try p
printing
PRINT "or opening them to see what happens.
RETURN
"Segmenu":
ON Menuitem GOSUB "Main", "Seg1", "Seg2", "Seg3", "Memory
RETURN
"Main":
PRINT "This is part of the main segment
RETURN
SEGMENT
"Seg1
PRINT "This is part of the 1st segment
SEGMENT RETURN
SEGMENT
"Seg2
PRINT "This is part of the 2nd segment
SEGMENT RETURN
SEGMENT
"Seg3
PRINT "This is part of the 3rd segment
SEGMENT RETURN
SEGMENT
"Memory
X&=MEM(-1)
PRINT "Memory = ";X&
SEGMENT RETURN
SEGMENT
"DisplayFINDERINFO":
CLS
Mes$(0)="Data file(s) should be loaded
Mes$(1)="Data file(s) should be printed
PRINT "Message% = ";Message%;" Therefore... "; Mes$( Message%)
PRINT "Count% = ";Count%; "file(s) have been passed to this
application
PRINT "Filenames are:
PRINT"Name","Type","Vol
FOR C=0 TO Count%-1
PRINT Name$(C),MKI$(Type&(C)),Vol%(C)
NEXT C
SEGMENT RETURN