Author: Eric Soldan (rev. Dave Lyons)
Year: 1989
... discusses handling nearly-out-of-memory situations when working with the IIgs tools.
Apple II
Technical Notes
_____________________________________________________________________________
Developer Technical Support
Apple IIgs
#51: How to Avoid Running Out of Memory
Revised by: Dave Lyons September 1990
Written by: Eric Soldan January 1989
This Technical Note discusses handling nearly-out-of-memory situations when
working with the IIgs tools.
Changes since January 1989: Retitled from "Reserving Memory for the Toolbox."
Noted that many toolbox calls require 16K or 32K of memory to be allocatable
for reliable operation.
_____________________________________________________________________________
Introduction
Running out of memory is a concern for most every application. Working with
the Toolbox makes monitoring this situation a little more difficult since your
application is not the only one allocating memory.
Low-level toolbox functions (for example, QuickDraw II calls) require that a
16K block of memory be allocatable, while high-level routines (for example,
the Window Manager) require that a 32K block of memory be allocatable. Apple
does not guarantee that toolbox functions behave reasonably if there is less
memory available, and the tools are not stress-tested with less than the
minimum required memory available.
Since the toolbox assumes reasonable memory-allocation requests succeed, just
waiting for an out-of-memory error is not adequate memory management. To make
your application work reliably in low-memory situations, you need a method of
ensuring that the toolbox gets memory when it needs it. This Note describes
two approaches.
How Much Memory Can Be Allocated
There's no way to tell how much memory can be allocated without actually
trying to allocate it.
MaxBlock tells you the size of the largest single free block, but this doesn't
take into account purgeable blocks, compaction, and out-of-memory routines
(see Apple IIgs Toolbox Reference, volume 3). FreeMem and RealFreeMem cannot
tell you how badly fragmented the memory is, and they do not take into account
out-of-memory routines.
A Suggested Method
A method of checking for a nearly-out-of-memory condition is to have your own
purgeable handle just for this task. If the handle has not been purged, then
you have plenty of memory for the toolbox, and in the worst case, the toolbox
purges your handle if it needs the RAM.
The less often your purgeable handle gets purged, the better performance you
get in nearly-out-of-memory situations. Therefore, you should arrange for
other purgeable memory, not necessarily belonging to your application, to be
purged before your handle. For example, you want dormant applications to be
purged, rather than having your handle get repeatedly purged and reallocated.
So the purge level of this handle should be one.
The check to see if a handle has been purged is very fast. If it has been
purged, you have to try to reallocate it. Reallocating a handle is not a fast
process, so the fewer times the handle is purged, the faster the check is and
the better your performance. Unless you are in a nearly-out-of-memory
situation, the handle should not be purged at all, and you should have
virtually no overhead for this process.
This technique can be implemented as follows:
appStart
;
; Somewhere at start, create a purgeable handle of size N,
; called "loMemHndl", purge level 1.
;
rts
******************
;
; Here's an example of checking for nearly-out-of-memory:
;
jsr preCheckLoMem
bcc goForIt
bcs HandleError ;Handle errors appropriately.
goForIt (_ToolboxCall[s]) ;Make as many as needed.
;
; Here you can make your toolbox calls. Since you prechecked
; for nearly-out-of-memory conditions, you should have no memory
; errors at this point.
;
; You could also check after calls, as shown here:
;
(_ToolboxCall)
jsr checkLoMem ;Call this to see if low.
bcc noError
bcs HandleError ;Take care of errors.
noError jsr lifeIsGood
.
.
.
rts
******************
;
; Here are some sample routines to check for the nearly-out-of-
; memory condition.
;
checkLoMem bcs retErr
preCheckLoMem lda [loMemHndl]
ldy #2
ora [loMemHndl],y
beq gotPurged
lda #0
clc
rts
gotPurged (Try reallocating it into loMemHndl, purge level 1.)
(If you can't, you will get a $0201 error. You may wish to
return the $201 error, or you may wish to change it into
your own error code.)
;
retErr rts ;This is a single exit point
;whether errors were present
;or not.
You can determine the size of this purgeable handle, but like determining what
size stack is adequate for an application, there is no single "right" answer.
There are different considerations for size of the purgeable handle for each
application, and these may change during the development process. Use your
best judgement, keeping in mind that high-level toolbox routines require a 32K
block.
An Alternative
For better control over when your handle is purged or disposed, you can write
an out-of-memory routine as described in the Memory Manager chapter of Apple
IIgs Toolbox Reference, volume 3. Out-of-memory routines have the opportunity
to free up memory before or after the Memory Manager attempts to purge
purgeable handles, and this manual contains a sample of such a routine.
Further Reference:
_____________________________________________________________________________
o Apple IIgs Toolbox Reference, Volumes 1-3