|
Technote 1128Understanding Open Transport Memory ManagementBy Quinn "The Eskimo!" |
CONTENTSIntroducing OT Memory Management | This Technote describes how Open Transport's interrupt-safe memory management system works, and how you can use it for best effect in your software. This Technote is directed at advanced programmers writing Open Transport client or kernel code. |
Introducing OT Memory ManagementOpen Transport provides many different interrupt-safe memory allocation routines. These include Pools of PowerOT memory management is layered on top of four classes of memory pools:
Open Transport memory pools are implemented by the Apple Shared Library Manager (ASLM)
Pool ParametersThe following tables gives the basic parameters of the various Open Tranpsort memory pools.
Notes:
|
Using OT Memory EffectivelyThis section describes various hints and tips for using the OT memory management system effectively. OT Routines and their Pool UsageThe following table is a summary of the common OT routines that allocate memory, the amount of memory they allocate, and the pool from which they allocate.
Notes:
Examining Memory Pools in MacsBugThe above analysis was done empirically, by calling each routine repeatedly while recording the effect on each memory pool. While OT provides no programming interface for measuring the usage of its memory pools, you can easily find the pools in MacsBug. First, you will need to find the debug version of Open Transport -- available via links on the OT web page -- and extract the "OT Debugger Prefs" file, included as part of the install package: Open Tpt Debug Installer Open Transport Installer Open Transport Files OT Debugger Prefs You should copy the "OT Debugger Prefs" file to your MacsBug Preferences folder, then restart your machine.
Once you have the "OT Debugger Prefs" file installed, you can use it to find and display the various OT memory pools. The first step is to dump the OT globals. This is done differently on 68K and PowerPC, and is explained in the following sections. Dumping OT Globals on PowerPCOn PowerPC, you can dump the OT globals using the following command:
OT exports the address of the OT globals as a CFM symbol,
Given the address of a pool, you can do a number of things with it:
Dumping OT Globals on 68KOn 68K, the procedure is slightly more complex. The first step is to find the address of the OT global. You do this using the following MacsBug command:
The first command switches the current MacsBug target zone to the system heap. The next command disassembles a function that returns the address of the OT globals. The line at
After dumping the OT globals, you can proceed as in the PowerPC case. Controlling Client Pool ParametersAs described above, the OT client pool for an application is allocated in the application heap when you call You can obtain more control over your client pool by using the ASLM programming interface. If you have already initialized a connection to ASLM,
To use this technique, you must call
The additional parameters to The following code snippet demonstrates this technique. It first creates a subsidiary zone within the application heap (whose size is calculated to consume the entire heap, minus some memory for use by the toolbox). It then calls
|
Advanced TopicsThis section describes some of the more advanced issues in the realm of OT memory management. Specifically, the section describes how the OT shared client and kernel pools grow and shrink over time. Before tackling this, you need to learn about another API call you can make to alter the behavior of the OT memory system.
|
#ifdef __cplusplus extern "C" { #endif extern OSStatus OTSetMemoryLimits(size_t growSize, size_t maxSize); #ifdef __cplusplus } #endif |
The growSize
parameter is the amount by which OT should grow the kernel pool right now. When you call the routine, OT immediately tries to grow the kernel pool by this amount. The maxSize
parameter is the new maximum size of the kernel pool. OT will never grow the kernel pool larger than this amount.
OTSetMemoryLimits
also implicitly sets an internal Open Transport variable called fServerMode
. If you call OTSetMemoryLimits
with a positive growSize
value, fServerMode
is incremented. If you call it with a zero value, fServerMode
is decremented. If fServerMode
is non-zero, OT will never downsize the shared client or kernel pools. To be a good citizen, server software should call OTSetMemoryLimits
with a positive growSize
when it starts up, and a zero growSize
when it shuts down.
Finally, if you grow the kernel pool by more than 20 KB, OTSetMemoryLimits
will also grow the shared client pool by 10% of the growSize
value.
OTSetMemoryLimits
is only of use to server software which must handle extremely 'bursty' connection patterns or many connections in parallel. By increasing the maximum size of the kernel pool, the server can handle more connections in parallel. By growing the kernel pool immediately (rather than as each connection is created), the server can handle these parallel connections as soon as it's started, rather than waiting for the kernel pool to grow through usage. By never downsizing the kernel pool, the server can handle many connections simultaneously even after a long period of inactivity.
OTSetMemoryLimits
must be called at system task time and returns an error result if it can't grow the kernel pool by the specified amount.
IMPORTANT: |
Note: |
Note: |
When OT attempts to grow a pool, it uses a binary back-off algorithm to do so. It starts by attempting to grow the pool by getting one big block of memory from the Mac OS Memory Manager. If a block of that size is not available, it halves the size requested and tries again. This process terminates when either OT has grown the pool the requested amount, or the block size shrinks below 10 KB.
ASLM memory pools have the ability to shrink. A memory pool is made up of a number of discontiguous memory blocks that have been allocated from the Mac OS Memory Manager. When a pool is downsized, each Mac OS memory block is examined to see if it is empty. If it is, that memory block is released back to the Mac OS Memory Manager.
OT memory pools are downsized at the following points:
CloseOpenTransport
or an application quits without calling CloseOpenTransport
) and OT is not in server mode, OT downsizes the shared client and kernel pools. InitOpenTransport
), it downsizes the kernel pool if OT is not in server mode. InitOpenTransportUtilities
), OT downsizes the port pool. OTSetupConfigurator
or OTStartupConfigurator
entry points. OT maintains a hard limit on the upper bound of the size of the kernel pool. Clients can set this limit using the OTSetMemoryLimits
routine. This poses the question: What is the initial value for this limit? Out of the box, OT sets this limit to 10% of the physical memory on the machine (as returned by gestaltPhysicalRAMSize
). This strikes a balance between providing enough buffer space for networking while preventing OT from consuming all the user's memory.
When the kernel is loaded for the first time, OT creates the kernel pool at the initial size specified above. However, each time the kernel loads (including the first time), OT forces the kernel to grow to be at least 96 KB before finishing the load. This mechanism allows the kernel pool to be small while the kernel is unloaded, but grow quickly when the kernel loads.
SummaryOpen Transport provides a reliable, flexible, and interrupt-safe memory management system. By understanding how it works, you can avoid some common pitfalls and still write code that allocates memory at interrupt time. Finally. |
|
Thanks to Mark Cookson, Steve Kalkwarf, Rich Kubota and Brad Suinn.
Technotes
Previous Technote | Contents | Next Technote