Segment Management (68K-Based Applications Only)
This section describes the basic issues involved in segmenting an application. These issues apply to 68K-based applications but not to applications built to run native on Power Macintosh computers.The Power Macintosh Doesn't Require Segmentation
Segmentation is not an issue for native Power Macintosh applications because on a Power Macintosh computer there is no segmentation of the application's code--the Virtual Memory Manager and the Process Manager handle the task of keeping required code in memory. MacApp's code to initialize segment handling, described in "Initializing MacApp's Segment Management," beginning on page 71, uses theqSegments
flag to control compilation, ensuring that segmentation code is included only for applications that need it.Segmenting a 68K Macintosh Application
For the 68K-based Macintosh, segmentation is an important issue.
Inside Macintosh: Processes describes the Segment Manager and explains why there is a need to divide an application's code into segments that can be loaded into memory on demand. If your application is running on a Macintosh computer with enough memory, many of your code segments (perhaps even all of them) can be resident in memory simultaneously. However, effective segmentation lets your application
If you don't specify otherwise, the segments in your application will use 16-bit addressing and will be limited in size to 32 KB. Global data will also be limited to 32 KB. Sixteen-bit addressing results in a smaller jump table and more efficient code, but it has these potential drawbacks:
- run in a smaller memory partition
- run on a greater number of machines
- run more efficiently
- You may spend a lot of time adjusting the size of your segments to avoid the 32 KB limit.
- You may run out of space for global data.
- You may run out of space in the jump table. (Once the jump table is full, you cannot declare any new methods.)
Segmentation Strategies
As a result of these trade-offs, there are a number of possible strategies for controlling segmentation in your application.Using ModelFar Addressing to Create Large Segments
If you build your application using the-ModelFar
build option (see
Appendix A), the linker will use 32-bit addressing for code and data segments, eliminating the 32 KB size limitation. Although this approach is simple, it can lead to inefficient code, and should only be used for applications with legitimate size requirements. And even if you build with the-ModelFar
option, you should still follow the strategy described below in "Putting Related Code in the Same Segment."Avoiding Jump-Table Limits
Another way to minimize size limitations is to build your application with the-CFM68K
build option. This option specifies that the application will use CFM-68K, the 68K Macintosh equivalent of the Power Macintosh Code Fragment Manager. CFM-68K uses 16-bit addressing, so it creates efficient code, but its implementation allows much more room for jump-table entries and global data.Creating Segments of Minimal Size
Another strategy for segmenting your application is to organize segments so that they are as small as possible. This ensures that the application heap will contain only code that is needed, increasing the amount of memory available. However, using small segments can lead to excessive segment load calls, which are triggered when a needed function is not present in memory.Putting Related Code in the Same Segment
A strategy used in the MacApp class library is to put functions that are used together in the same segment. For example, routines used only in initializing the application are placed in one segment. That segment is loaded during initialization, but it may later be replaced by another segment, because it won't be needed again until the next time the application is launched.Creating Segments
MacApp uses compiler segment directives such as the following to specify the segment for a section of code:
#pragma segment AResThis tells the compiler that all code following the directive belongs in theARes
segment (but see the following section for information on remapping segments). The directive remains in effect until another segment directive is encountered.
MacApp and the sample applications distributed with MacApp use the following segment-naming conventions:
- Note
- Putting a routine in a segment named
ARes
does not automatically make the code in that routine resident. See "The 'res!' Resource," beginning on page 81, for information on how to make a segment resident.
Some of MacApp's segment names are shown in Table 3-3, with examples of the functions each segment contains. (For more information, see "Recipe--Defining Segment Names for Your Application," beginning on page 553.)
- Each method or routine is prefaced with a segment directive, indicating the segment in which the code is to be located.
- A segment name indicates the function of the code segment.
- All routines used for a specific function are included in the same segment. For example, all code for reading files is stored in the segment
AReadFile
.
Table 3-3 Table 3-3 MacApp segment names and descriptions
Segment name Functions stored in the segment (continued) AClose
Routines for closing documents and data structures ADebug
Debugging code ADoCommand
Commands for performing operations: TSketcher::TrackMouse
AInit
Functions used only when the application is launched: IYourApplication
ANonRes
,
ANonRes2
, ...Most routines should be nonresident, so most applications need more than one segment for nonresident code AOpen
Routines for opening documents and data structures: DoMakeViews
,DoMakeWindows
,IYourDocument
,DoMakeDocument
,IYourView
AReadFile
Routines for reading from disk: DoRead
,DoInitialState
ARes
,ARes2
, ...Resident routines (called often); code should be resident only if calling it must not move memory (for example, memcpy
), or if it is called every time through the event loop (such asGetSleepTime
):DoSetCursor
,DoIdle
ASelCommand
Code that determines which command to perform in response to an event ATerminate
Functions used only when the application is terminated AWriteFile
Routines for saving files to disk: DoNeedDiskSpace
,DoWrite
MADebugger
MacApp debugging code (generated by qDebug
,qUserFlag[1-3]
)Main
Main resident segment; contains system library routines and crucial code for starting the application Remapping Segment Names
If your application follows the segment-naming convention described in the previous section, you may be surprised to find that a segment name you used is nowhere to be seen in a link map for the application. (The next section describes how to create a link map.) The likely explanation is that, in fine tuning its segmentation, MacApp remapped your segment name.Information about how MacApp remaps segment names can be found in the file
{MADependencies}Definitions_68K
, which is described in Appendix A. For example,Definitions_68K
contains the following lines:
-sn AReadFile=GReadFile -sn MAFileRead=GReadFileThese lines indicate that any functions placed by a#pragma
statement in the segmentAReadFile
will be remapped to the segmentGReadFile
(or Global Read File), as will any functions placed in the segmentMAFileRead
. So any code you place in theAReadFile
segment ends up in the same segment as MacApp's file-reading code.
Segment remapping can be a source of confusion. For example, you might place a small number of functions in a segment, then get a link error that the segment has overflowed. The explanation may be that your code has been remapped to a segment that was already nearly full with other code.
- Note
{MADependencies}
is a notation used in the MPW programming environment. When you execute a command line containing "{MADependencies}
" (without the quotation marks) in the MPW worksheet, the expression is expanded to the full directory name of the MacApp Dependencies folder, for example,YourHardDisk:MacApp:Tools:Dependencies.
On the plus side, you can use segment remapping as a tool to fine tune your code segmentation. It is usually easier to add or change
-sn
segment directives (in theOtherSegMappings
section of your application'sMAMake
file) than to modify a potentially large number of#pragma
statements located throughout your code. For more information see "Recipe--Defining Segment Names for Your Application," beginning on page 553.Creating a Link Map
To determine the exact segment location of each routine in your application, you can create a link map. With MPW and the MABuild tool, for example, you create a link map by building your application with a line like the following:
MABuild -link -map [other options] YourAppName > YourAppName.mapThe resulting link map file is named YourAppName.map
. Appendix A describes how to build an application with the MABuild tool. The Macintosh Programmer Workshop Reference provides information on link options.The 'seg!' Resource
MacApp uses the'seg!'
resource to store information about segmentation. A'seg!'
resource contains a list of the segment names the application has in memory at the point of greatest memory usage. Greatest memory usage usually occurs when printing, or when launching the application to open or print an existing document.MacApp uses the information in the
'seg!'
resource in calculating the memory requirements for the application (see page 65). MacApp defines its own'seg!'
resource in the filedefaults.r
:
#if !qPowerPC resource 'seg!' (kDefaultSegResource, #if qNames "Default seg!", #endif purgeable) { { "GNonRes"; "GClipboard"; "GClose"; "GFile"; "GOpen"; "GSelCommand"; "GDoCommand"; "BBNonRes"; "BBOpen"; "GNonRes2"; "GPrint"; "GReadResource"; }; }; #endif qPowerPCNote that this resource is defined only if the application is not built for a Power Macintosh (#if !qPowerPC
).An application can have more than one
'seg!'
resource, so you have two options in 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.
- Note
- When including MacApp segments, be sure to use MacApp's remapped segment names.
The 'res!' Resource
The'res!'
resource defines those segments that should always be resident in the heap. (MacApp makes a segment permanently resident with the global routineSetResidentSegment
.) Memory used by resident segments is unavailable for other operations throughout the life of the application, so you should avoid unnecessarily making a segment 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 or because the code is called frequently (for example, every time through the event loop). You might make a segment resident if it contains functions that are called during interrupt time, when a segment can't be loaded.
- Note
- Resident segments are loaded into the application's heap during initialization and locked, so that they are always available while the application is running. For this reason it is very likely that every segment present in a
'res!'
resource will also be listed in a'seg!'
resource.You can minimize the number of resident segments (and avoid segment loading) by putting routines that call each other in the same segment so that the calls will not require the use of a jump table. However, routines declared as
virtual
are always dispatched through the jump table.MacApp defines a
'res!'
resource in the fileMemory.r
. An application can have more than one'res!'
resource, so you can add to MacApp's resident segments by adding your own'res!'
resource, as the IconEdit sample application does in the fileIconEdit.r
:
#if !qPowerPC resource 'res!' (kIconEditApp, #if qNames "IconEditApp", #endif purgeable) { { "ARes"; }; }; #endif qPowerPC
- Note
- A detailed technical discussion of MacApp segmentation issues can be found in the technical note "PT 21--MacApp Segmentation Illuminations," available from Apple Developer Technical Services.