Please consider a donation to the Higher Intellect project. See or the Donate to Higher Intellect page for more info.

Memory Manager

From Higher Intellect Vintage Wiki
Jump to navigation Jump to search

The Memory Manager is the part of the Macintosh Operating System that controls the dynamic allocation of memory space. Ordinarily, you need to access information only within your own application’s heap, stack, and A5 world. Occasionally, however, you might need to use the Memory Manager to allocate temporary memory outside of your application’s partition or to initialize new heap zones within your application partition. You might also need to read a system global variable to obtain information about the environment in which your application is executing.

The Memory Manager provides a large number of routines that you can use to perform various operations on blocks within your application partition. You can use the Memory Manager to

  • set up your application partition
  • allocate and release both relocatable and nonrelocatable blocks in your application heap
  • copy data from nonrelocatable blocks to relocatable blocks, and vice versa
  • determine how much space is free in your heap
  • determine the location of the top of your stack
  • determine the size of a memory block and, if necessary, change that size
  • change the properties of relocatable blocks
  • install or remove a grow-zone function for your heap
  • obtain the result code of the most recent Memory Manager routine executed

The Memory Manager also provides routines that you can use to access areas of memory outside your application partition. You can use the Memory Manager to

  • allocate memory outside your partition that is currently unused by any open application or by the Operating System
  • allocate memory in the system heap

This section describes the areas of memory that lie outside your application partition. It also describes multiple heap zones.

Temporary Memory

In the Macintosh multitasking environment, your application is limited to a particular memory partition (whose size is determined by information in the 'SIZE' resource of your application). The size of your application’s partition places certain limits on the size of your application heap and hence on the sizes of the buffers and other data structures that your application can use.

If for some reason you need more memory than is currently available in your application heap, you can ask the Operating System to let you use any available memory that is not yet allocated to any other application. This memory, called temporary memory, is allocated from the available unused RAM; in general, that memory is not contiguous with the memory in your application’s zone.

Your application should use temporary memory only for occasional short-term purposes that could be accomplished in less space, though perhaps less efficiently. For example, if you want to copy a large file, you might try to allocate a fairly large buffer of temporary memory. If you receive the temporary memory, you can use the large buffer to copy data from the source file into the destination file. If, however, the request for temporary memory fails, you can instead use a smaller buffer within your application heap. Although the use of a smaller buffer might prolong the copy operation, the file is nonetheless copied.

One good reason for using temporary memory only occasionally is that you cannot assume that you will always receive the temporary memory you request. For example, if two or more applications use all available memory outside the system partition, then a request by any of them for some temporary memory would fail.

Another strategy for using temporary memory is to use it, when possible, for all nonessential memory requests. For example, you could allocate window records and any associated window data using temporary memory. This scheme allows you to keep your application partition relatively small (because you don’t need space for nonessential tasks) but assumes that users will not fill up the available memory with other applications.

Multiple Heap Zones

A heap zone is a heap (that is, an area in which you can dynamically allocate and release memory on demand) together with a zone header and a zone trailer. The zone header is an area of memory that contains essential information about the heap, such as the number of free bytes in the heap and the addresses of the heap’s grow-zone function and purge-warning procedure. The zone trailer is just a minimum-sized block placed as a marker at the end of the heap zone. (See “Heap Zones” on page 2-19 for a complete description of zone headers and trailers.)

When your application is executing, there exist at least two heap zones: your application’s heap zone (created when your application was launched) and the system heap zone (created when the system was started up). The system heap zone is the heap zone that contains the system heap. Your application heap zone (also known as the original application heap zone) is the heap zone initially provided by the Memory Manager for use by your application and any system software routines your application calls.

Ordinarily, you allocate and release blocks of memory in the current heap zone, which by default is your application heap zone. Unless you change the current heap zone (for example, by calling the InitZone or SetZone procedures), you do not need to worry about which is the current zone; all blocks that you access are taken from the current heap zone, that is, your application heap zone.

Occasionally, however, you might need to allocate memory in the system heap zone. System software uses the system heap to store information it needs. Although, in general, you should not allocate memory in the system heap, there are several valid reasons for doing so. First, if you are implementing a system extension, the extension can use the system heap to store information. Second, if you want the Time Manager or Vertical Retrace Manager to execute some interrupt code when your application is not the current application, you might in certain cases need to store the task record and the task code in the system heap. Third, if you write interrupt code that itself uses heap memory, you should either place that memory in the system heap or hold it in real RAM to prevent page faults at interrupt time, as discussed in the chapter “Virtual Memory Manager” in this book.

You can create additional heap zones for your application’s own use by calling the InitZone procedure. If you do maintain more than one heap zone, you can find out which heap zone is the current one at any time by calling the GetZone function, and you can switch zones by calling the SetZone procedure. Almost all Memory Manager operations implicitly apply to the current heap zone. To refer to the system heap zone or to the (original) application heap zone, you can call the functions SystemZone or ApplicationZone. To find out which zone a particular block resides in, you can call the HandleZone function (if the block is relocatable) or the PtrZone function (if it’s nonrelocatable).

Once you have created a heap zone, it remains fixed in size and location. For this reason, it usually makes more sense to use the undivided application heap zone for all of your memory-allocation needs. You might, however, choose to initialize an additional heap zone in circumstances like these:

  • If you are implementing a software development environment and want to launch applications within the development environment’s partition, you can initialize a heap zone for the launched application to use as its heap zone.
  • If you want to avoid heap fragmentation but cannot prevent allocation of small nonrelocatable blocks in the middle of your program’s execution, you could, soon after your application starts up, allocate a small heap zone to hold the nonrelocatable blocks you allocate during execution.
  • If you need to resize a particular handle quite often, you can minimize the resizing time by creating a heap zone whose size is set to the maximum size the handle will ever be assigned. Because there is only one relocatable block in the new heap zone, the resizing is likely to happen more quickly than if that block were in the original heap zone (where other relocatable blocks in the zone might need to be moved).

Before deciding to create additional heap zones, however, make sure that you really need to. Maintaining multiple heap zones requires a considerable amount of extra work. You must always make sure to allocate or release memory in the correct zone, and you must monitor memory conditions in each zone so that your application doesn’t run out of memory.

The System Global Variables

Just as the Toolbox stores information about your drawing environment in a set of QuickDraw global variables within your application partition, the Operating System and Toolbox store information about the entire multiple-application environment in a set of system global variables, also called low-memory global variables. The system global variables are stored in the lowest part of the physical RAM, in the system partition.

Most system global variables are intended for use by system software only, and you should never need to read or write them directly. Current versions of system software contain functions that return values equivalent to most of the important system global variables. Use those routines whenever they are available. However, you might occasionally need to access the value of a system global variable to maintain compatibility with previous versions of system software, or you might need to access a system global variable whose value no equivalent function returns. The MPW interface file SysEqu.p defines the memory locations at which system global variables are stored in the latest version of system software. For example, SysEqu.p contains lines like these:

   RndSeed = $156;  {random number seed (long)}
   Ticks = $16A;  {ticks since last boot (unsigned long)}
   DeskHook = $A6C;  {hook for painting desktop (pointer)}
   MBarHeight = $BAA;  {height of menu bar (integer)}

You can use these memory locations to examine the value of one of these variables. See “Reading and Writing System Global Variables” on page 2-8 for instructions on reading and writing the values of system global variables from a high-level language.

You should avoid relying on the value of a system global variable whenever possible. The meanings of many global variables have changed in the past and will change again in the future. Using the system global variables documented in Inside Macintosh is fairly safe, but you risk incompatibility with future versions of system software if you attempt to access global variables defined in the interface files but not explicitly documented.

Even when Inside Macintosh does document a particular system global variable, you should use any available routines to access that variable’s value instead of examining it directly. For example, you should use the TickCount function to find the number of ticks since startup instead of examining the Ticks global variable directly.

See Also