Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Programmer's Guide to MacApp / Part 2 - Working With MacApp
Chapter 24 - Working With Memory and Failure Handling


Memory Overview

MacApp provides a sophisticated memory management system, described in detail in Chapter 3, "Core Technologies." MacApp's memory management was designed to meet two important goals:

Ensuring That Critical Memory Requests Succeed

To meet the first goal, MacApp defines two types of memory requests, permanent and temporary.

You use permanent memory requests for most items your application allocates, such as handle and pointer memory requests. If a permanent memory request fails, no harm is done. A user may be unable to open an additional window or perform some other noncritical operation, but the application continues running and other operations can still be performed. Memory from a successful permanent allocation remains in use until you specifically free it.

You use temporary memory requests for allocations that must not fail. Suppose a user attempts to save a document and your application requests memory needed to write the document's data. If the request fails, the user will be unable to save the document. Because changes to the document will be lost, it is critical that the allocation not fail. Memory from a successful temporary allocation can be purged by MacApp (subject to your control) to make room for another allocation.

As long as there is sufficient memory in the application heap, all requests are satisfied from the available memory. It is only when a request cannot be satisfied that its type, temporary or permanent, becomes important. When a memory request can't be satisfied, the operating system calls the application's grow-zone procedure to attempt to free more memory. MacApp's grow-zone procedure, GrowZoneProc, uses a different algorithm for a temporary request than for a permanent request. That algorithm, together with the application's temporary reserve and low-space reserve, ensures that all temporary requests are satisfied.

Managing Object Allocation Efficiently

MacApp uses a global heap object, gObjectHeap, to store objects created by your application. The global heap object allocates objects from a block of nonrelocatable memory it manages. Using nonrelocatable memory for the object heap reduces the number of blocks that the Toolbox Memory Manager has to manage in the application heap.

The heap object can allocate a large number of small objects efficiently, and it reuses the memory released when an object is freed. However, memory managed by the object heap cannot be used by the application for nonobject allocations. (See "Allocating Objects," beginning on page 72, for more information on the global heap object.)

MacApp makes it possible for you to manage your own object allocation rather than use the global heap object. For a description of how to modify object creation and deletion, see "Replacing MacApp's Global New and Delete Operators," beginning on page 74.

Allocating Permanent and Temporary Memory

MacApp maintains a flag, pTemporaryAllocation, to control the allocation of temporary and permanent memory. Since system requests are temporary and tend to occur at unpredictable times, the pTemporaryAllocation flag is normally set to TRUE so that memory requests will be temporary by default. You use the global TemporaryAllocation routine to set pTemporaryAllocation, as described in "Allocating Permanent Memory," beginning on page 546.

Figure 24-1 shows MacApp's global memory allocation routines. The PermAllocation method is provided for compatibility with previous versions of MacApp--it sets the value of the pTemporaryAllocation flag to the opposite of the passed value.

Figure 24-1 MacApp's global memory allocation routines

Note
The code samples in the first part of this chapter (covering memory operations) do not include failure handling. Failure handling is demonstrated starting on page 560.

MacApp's Memory Allocation Routines

MacApp defines several memory allocation routines that request permanent memory. Each of these routines sets the pTemporaryAllocation flag to FALSE, calls a corresponding Toolbox routine to allocate the requested memory, then restores the previous state of the flag:

NewPermPtr
The NewPermPtr routine calls NewPtr to allocate a pointer to a permanent memory allocation.
SetPermPtrSize
The SetPermPtrSize routine calls SetPtrSize to set the size of a permanent memory allocation pointed to by a pointer. The resized memory allocation is still permanent.
NewPermHandle
The NewPermHandle routine calls NewHandle to allocate a handle to a permanent memory allocation.
SetPermHandleSize
The SetPermHandleSize routine calls SetHandleSize to set the size of a permanent memory allocation pointed to by a handle. The resized memory allocation is still permanent.
When the pTemporaryAllocation flag is in its default state of TRUE, the Toolbox routines NewPtr, SetPtrSize, NewHandle, and SetHandleSize request temporary memory.

Allocating Permanent Memory

When you create handles or pointers for long-lived data, such as document or window data structures, you should allocate them with NewPermHandle or NewPermPtr.

You can also call the TemporaryAllocation routine to set pTemporaryAllocation, passing the value FALSE to specify permanent allocation. All subsequent allocations will be permanent until the flag is set to TRUE. The following code fragments show two ways to perform the same task--make a permanent memory request for two handles of arbitrary size:

IMPORTANT
When you set the pTemporaryAllocation flag by calling TemporaryAllocation, it stays the same for any number of subsequent memory requests. However, MacApp sets allocation to temporary (sets the pTemporaryAllocation flag to TRUE) in certain circumstances. So your application should specifically set allocation to permanent when necessary and not assume it is still permanent from a previous operation.
Whenever the TemporaryAllocation routine changes the pTemporaryAllocation flag from FALSE to TRUE, MacApp rebuilds its temporary and low-space reserves. Frequent rebuilding can lead to purging and compacting of memory, which can harm performance, so you should avoid excessive changes to the allocation state.

There is another reason to specify permanent memory only when it is absolutely necessary. If you set pTemporaryAllocation to FALSE and the following code causes a segment load or some other system memory request, the application could run out of permanent memory and fail (or even crash), when a temporary request would have succeeded. Minimizing the number of times you specifically ask for permanent memory will maximize MacApp's ability to guarantee that crucial memory requests are successful.

Allocating Temporary Memory

Your application uses temporary memory requests for allocations that cannot fail, such as memory needed in the course of saving a document or quitting the application. MacApp uses temporary memory for allocating code segments, WDEFs and CDEFs, error dialog boxes, and critical resources.

Handles and pointers allocated for short-term use, such as those allocated and disposed of in the same routine, can also be allocated with a temporary request. Since the normal state for the pTemporaryAllocation flag is TRUE, or temporary, routines such as NewHandle and NewPtr will default to temporary requests. However, if an allocation must not fail, you should specifically set pTemporaryAllocation to TRUE. Consider the following two code fragments:

Allocating Memory for Objects

MacApp uses a global object, gObjectHeap, to allocate memory for your application's objects. The object heap is initialized to a default size determined by your application's 'mem!' resources, which are described beginning on page 551. The initial memory allocation for the object heap is made in permanent memory. The object heap allocates objects from its block of memory until that memory is exhausted--then it increases the size of the heap by an increment size that is also defined by your application's memory resources.

When the object heap has to increase its size, it allocates additional permanent memory using the Toolbox routine NewPtr.

Allocating Memory for Lists

MacApp maintains an additional flag, pAllocateObjectsFromPerm, that determines whether the memory used by an array object should be grown with a permanent or a temporary request.

IMPORTANT
Although the name pAllocateObjectsFromPerm might sound like it controls the request type (permanent or temporary) for object allocations, it does not. It used to, but now MacApp uses pAllocateObjectsFromPerm only when setting the array size in the TDynamicArray class.
MacApp's array classes include many list classes that descend from TDynamicArray. The TDynamicArray::SetArraySize method calls GetPermObjectAllocationState to get the current value of pAllocateObjectsFromPerm. If the value is TRUE, SetArraySize calls SetPermHandleSize; otherwise, it calls SetHandleSize.

If your application performs an operation that must not fail and that operation can cause an array object to grow (for example, it can add an entry to a list object), you can specify temporary memory with code like the following:

// Make sure all subsequent array requests are temporary.
Boolean oldArrayPerm = AllocateObjectsFromPerm(FALSE);
// Perform operation that may cause list to grow.
.
.
.
// Restore previous state of flag.
oldArrayPerm = AllocateObjectsFromPerm(oldArrayPerm);

Allocating Memory for List and Objects

As a final example of making a temporary-memory request for an allocation that must not fail, consider the case where both an object allocation and a list allocation must not fail. In the code fragment that follows, the application must create and post a critical command. To ensure that the command object is created, you must set pTemporaryAllocation to TRUE (for temporary). To ensure that posting the command (which inserts the command into the application's command list, causing the list to grow) succeeds, you must also set pAllocateObjectsFromPerm to FALSE.

// Make sure object allocation is temporary.
Boolean oldTemp = TemporaryAllocation(TRUE);

// Create critical command object.
TCriticalCmd theCriticalCmd = new TCriticalCmd;

// Make sure all subsequent array requests are temporary.
Boolean oldArrayPerm = AllocateObjectsFromPerm(FALSE);

// Perform operation that may cause list to grow.
this->PostCommand(theCriticalCmd);

// Restore state of pAllocateObjectsFromPerm flag.
oldArrayPerm = AllocateObjectsFromPerm(oldArrayPerm);

// Restore previous state of pTemporaryAllocation flag.
oldTemp = TemporaryAllocation(oldTemp);
Note
Another option is to create a TCriticalCmd object at startup and reuse it whenever necessary. Then the command will always be available when it is needed.

Allocating Master Pointers for the Application

Application initialization is described in detail in Chapter 4, "Launching and Terminating an Application." As part of initialization, your application makes a call similar to one of the following two calls:

InitUMacApp(4);
or

InitUMacApp_Step3(4);
When expanded, the InitUMacApp macro includes a call to InitUMacApp_Step3. The value 4, passed as a parameter, tells MacApp's memory initialization to call the Toolbox routine MoreMasters four times. The MoreMasters routine allocates space for a block of master pointers. By calling this routine during MacApp initialization, the master pointers are allocated in the heap first, and so memory fragmentation is minimized.

Each call to MoreMasters creates a block of 64 master pointers. The number you pass to InitUMacApp or InitUMacApp_Step3 should equal the greatest number of dynamically allocated blocks of memory that your application will need at any one time, divided by 64.

'mem!', '68k!', and 'ppc!' Resources

MacApp uses the 'mem!' and 'ppc!' ('68k!' for a 68K application) resource types to specify several memory-related values for the application. Each of these resource types has the same format--five consecutive longint fields. The value of each field can be positive, negative, or 0. The five fields are used to specify, in order

For '68k!' and 'ppc!' resources, only the first two fields are normally used. The other fields are set to 0. MacApp's default 'mem!' resource, in the file Memory.r, is defined as follows:

resource 'mem!' (kBaseMacApp,
#if qNames
   "BaseMacApp",
#endif
   purgeable) {
   32 * 1024,  // Initial pointer-based object heap size.
   30 * 1024,  // Minimum amount to grow object heap.
   6 * 1024,   // Add to temporary reserve.
   6 * 1024,   // Add to permanent reserve.
   32 * 1024   // Base stack size.
};
This resource specifies default values for each of the five memory-related fields. During memory initialization, MacApp totals the values of the five fields for each 'mem!' resource in the application, including MacApp's default resource. It then adds the values from each '68K!' resource for 68K applications or the values from each 'ppc!' resource for Power Macintosh applications. For example, the 'ppc!' resource adds 30 KB to the permanent memory reserve.

MacApp then uses the totals computed from these resources to set the initial size for the heap object, set the heap object's increment, allocate temporary and low-space reserves, and set the application's stack size. Since you can specify negative numbers in these resources, you can shrink the values found in MacApp's default 'mem!' resource. For example, the default initial size for the heap object is 32 KB. If your application needs less memory for allocating objects, you can decrease this value by specifying a negative number in the first field of your own 'mem!' resource.

Note
For Power Macintosh applications, the 'cfrg' resource also has a field to specify stack size. Some integrated development environments allow you to directly specify a stack size using this resource, but MacApp ignores this resource and uses the value specified in the 'mem!' resource.
MacApp provides additional 'mem!' resources to accompany certain units:

"Determining the Size of Memory Reserves," beginning on page 65, provides information to help determine appropriate sizes for your application.

Note
Additional information about MacApp memory resource issues can be found in the technical note "PT 21--MacApp Segmentation Illuminations," available from Apple's Developer Technical Services.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
25 JUL 1996