Important: The information in this document is obsolete and should not be used for new development.
Recipes--Memory (68K Only)
The recipes and sample code in this section present a system for defining segment names and also demonstrate how to fine tune memory usage by defining'res!'
and'seg!'
resources for your application. These recipes all involve segments--thus they are used only by 68K applications.For detailed information on MacApp segmentation issues, see "Segmenting a 68K Macintosh Application," beginning on page 75.
Recipe--Defining Segment Names for Your Application
This recipe describes a strategy for naming segments in your application by combining two aspects of each routine you place in a segment: a short code for the unit the routine resides in and a second code based on when the code is called (the phase of application execution when the code is called). This strategy is based on the strategy used by MacApp itself.The unit part of the segment name can be something like the following (a partial list):
For each routine in your application, you create a segment name by combining the code for its unit and the code for when it is executed. For example, routines from the document unit for reading a document go in the DocReadFile segment. Routines for writing a document go in the
App
- For the application unit
Doc
- For the document unit
Pref
- For the preferences unit
View
- For the view unit
- The execution part of the segment name can be something like the following
- (a partial list):
Cursor
HandleCursor
andDoSetCursor
and related routines (called frequently from the main event loop)DoCommand
DoIt
,UndoIt
, andRedoIt
routinesHelp
- Balloon Help routines
Init
- Routines used only at application initialization (not resident!)
Patch
- Called from patches or VBL tasks (make resident)
- Printing routines
ReadFile
- Routines used in opening an existing document
Res
- Resident code (don't overuse)
SelCommand
Handle
routines (HandleEvent
,HandleKeyUp
, and so on) andDo
routines (DoEvent
,DoKeyUp
, and so on)WriteFile
- Routines used in saving a document
DocWriteFile
segment. Routines from the view unit that handle the cursor go in the ViewCursor segment.You specify a segment for a routine by placing a
#pragma
segment statement in your code just before the implementation of the routine. For example, the following line places a routine in the DocReadFile segment:
#pragma segment DocReadFileA #pragma segment statement remains in effect until the next such statement is encountered, so you should place a statement before each routine.Once you have established your segment-naming strategy, you will rarely have to change the
#pragma segment
statements in your code, which means you won't have to compile as often. You can manage segmentation at link time with-sn
directives in yourMAMake
file. For example, the following lines specify that the DocReadFile routine should be placed in the AReadFile segment, DocWriteFile in the AWriteFile segment, and ViewCursor in the ARes segment:
OtherSegMappings = -sn DocReadFile=AReadFile -sn DocWriteFile=AWriteFile -sn ViewCursor=AResFor large applications, you may have many-sn
directives, but the linker can process them efficiently. For more information on remapping segment names, see the following recipe.Recipe--Defining a 'res!' Resource
The'res!'
resource defines those segments that should always be resident in the application heap. For more information, see "The 'res!' Resource," beginning on page 81.To define a
'res!'
resource for your 68K MacApp application, you perform these steps:
The sample code in this recipe is from the IconEdit application.
- Identify code that should always be resident.
- Map related code to the same segment.
- Create a
'res!'
resource that lists your resident segments.
Identify Code That Should Always Be Resident
In general, you put code in a resident segment because you can't afford to have a segment load occur when you call that code. Such code might include
- routines called during interrupt time, when a segment can't be loaded
- routines such as
memcpy
that make use of dereferenced pointers into relocatable handles- performance-critical routines that are called every time through the event loop
Map Related Code to the Same Segment
There are two convenient ways to locate code in a particular segment:
The -sn linker directive is described in "Remapping Segment Names," beginning on page 79.
- You can specify a segment for a routine by placing a
#pragma
statement in your code just before the implementation of the routine. This mechanism is described in the previous recipe.- You can remap segments using the -sn linker directive.
Create a 'res!' Resource That Lists Resident Segments
A'res!'
resource simply lists the names of segments that should be made resident. The names correspond to those used in#pragma
statements or-sn
linker directives. The format is demonstrated by the IconEdit application's'res!'
resource, from the fileIconEdit.r
:
#if !qPowerPC resource 'res!' (kIconEditApp, #if qNames "IconEditApp", #endif purgeable) { { "ARes"; }; }; #endif qPowerPCThis resource defines just one resident segment, theARes
segment. MacApp uses your application's'res!'
resource in addition to its own, which is defined in the fileMemory.r
.Because MacApp remaps some of its segment names (according to information found in the file
{MATools}Definitions_68K
), segment names in the'res!'
resource may be different from segment names specified in the source code with#pragma
statements. You can create a link map (see "Creating a Link Map," beginning on page 80) and compare it with the complete set of'res!'
resources in your application. You can also examine a 'res!' resource in ResEdit using the'STR#'
template.
#if !qPowerPC resource 'res!' (kBaseMacApp, #if qNames "BaseMacApp", #endif purgeable) { { "Main"; "MAMain"; "ClassDescRes"; "GConstructorRes"; "GRes"; "GRes1"; "GRes2"; "GRes3"; "GRes4"; "GRes5"; "GRes6"; "BBRes"; "BBRes2"; "GError"; "AEObjSuppt"; #if qDrag "MADragRes"; #endif "MAScriptingRes"; "SADEV"; "INTENV"; "STDIO"; "STDCLIB"; "32-bit bootstrap"; #if qPerform "GPerformanceTools"; #endif }; }; #endif qPowerPCNote that MacApp's'res!'
resource is conditionally compiled--it is included only when the application is built to run on a 68K-based machine.Recipe--Defining a 'seg!' Resource
MacApp uses the'seg!'
resource to store information about segmentation. For more information, see "The 'seg!' Resource," beginning on page 80.To define a
'seg!'
resource for your 68K MacApp application, you perform these steps:
The sample code in this recipe is from the IconEdit application.
- Identify your application segments in memory at the point of greatest memory usage.
- Identify the MacApp segments in memory at the same point.
- Create a
'seg!'
resource that lists the identified segments.
Identify Segments in Memory at Greatest Memory Usage
Identifying your application's point of greatest memory usage, and the segments in memory at that point, is not a simple task. This point often occurs when printing, or when launching the application to open or print an existing document. Remember that any segment listed in a'res!'
resource is by definition resident and therefore is always part of your application's greatest memory usage.You can use the About This Macintosh command from the Apple menu to get a rough idea of the amount of memory your application uses at various times. Utility applications available for the Macintosh provide a more detailed snapshot. You can use a debugger such as MacsBug to examine the loaded segments at a particular point in program execution.
Using your best judgment and the information provided by any available utilities, you can make a good estimate of which segments to include in your
'seg!'
resource.Identify MacApp Segments Also in Memory
You can use the same techniques described in the previous section to identify MacApp segments in memory at your application's point of greatest memory usage. They will largely fall into one of two groups:
- segments containing MacApp code that supports the code in your application's segments (for example, if your greatest usage occurs while printing, MacApp's printing code will probably be loaded as well)
- segments from MacApp's
'res!'
resource (which are always resident)
Create a 'seg!' Resource That Lists the Segments
A'
seg!'
resource simply lists the names of segments that are in memory at the point of greatest memory usage. The following is the'seg!'
resource from the IconEdit sample application:
#if !qPowerPC resource 'seg!' (kIconEditApp, #if qNames "IconEditApp", #endif purgeable) { { "ARes"; "GNonRes"; "GClipboard"; "GClose"; "GFile"; "GOpen"; "GDoCommand"; "GSelCommand"; "GWriteFile"; "GReadFile"; "GFinder"; . . . // Some segments omitted. "GPrint"; "GReadResource"; }; }; #endif qPowerPCYour'seg!'
resource should list all the segments identified in the two previous steps of this recipe. Your application can have more than one'seg!'
resource, so you have two options for specifying the segments your application uses at its point of greatest memory usage:
- Include MacApp's
'seg!'
resource, along with one you define.- Add the segments from MacApp's
'seg!'
resource (or just the ones you know your application needs) to your'seg!'
resource, as IconEdit does in the example just shown.
- Note
- MacApp automatically counts as resident any segments marked as
preload
.