Mac OS X Reference Library Apple Developer
Search

Tracking Memory Usage

If you suspect your code is not using memory as efficiently as it could, the first step in determining if there is a problem is to gather some baseline data. Monitoring your code using one of the Apple-provided performance tools can give you a picture of your code’s memory usage and may highlight potential problems or point to areas that need further examination. The following sections describe the tools most commonly used for memory analysis and when you might want to use them.

Tracking Allocations With Instruments

The Instruments application is always a good starting point for doing any sort of performance analysis. Instruments is an integrated, data-gathering environment that uses special modules (called instruments) to gather all sorts of information about a process. Instruments can operate on your application’s shipping binary file—you do not need to compile special modules into your application to use it. The library of the Instruments application contains four modules that are designed specifically for gathering memory-related data. These modules are as follows:

You can add any or all of these instruments to a single trace document and gather data for each of them simultaneously. Being able to gather the data all at once lets you correlate information from one instrument with the others. For example, the Leaks instrument is often combined with the ObjectAlloc instrument so that you can both track the allocations and find out which ones were leaked.

After gathering data for your application, you need to analyze it. The following sections provide tips on how to analyze data using several of the memory-related instruments. For information on how to use the Leaks instrument, see “Finding Leaks Using Instruments.”

Analyzing Memory Allocations with the ObjectAlloc Instrument

You use the ObjectAlloc instrument to track the memory allocation activity for your application. This instrument tracks memory allocations from the time your application is launched until you stop recording data. The instrument shows you the allocations in terms of the number of objects created and the size (or type) of the objects that were created. In the icon viewing mode, the instrument displays a real-time histogram that lets you see changes and trends directly as they occur. It also retains a history of allocations and deallocations, giving you an opportunity to go back and see where those objects were allocated.

The information displayed by the ObjectAlloc instrument is recorded by an allocation statistics facility built into the Core Foundation framework. When this facility is active, every allocation and deallocation is recorded as it happens. For Objective-C objects, copy, retain, release, and autorelease messages are also recorded.

Using the Allocation Graph

In icon mode, the ObjectAlloc instrument displays a table with a listing of all memory blocks ever allocated in the application, as shown in Figure 1. The Category column shows the type of the memory block—either an Objective-C class name or a Core Foundation object name. If ObjectAlloc cannot deduce type information for the block, it uses “GeneralBlock-” followed by the size of the block (in bytes). The Net column shows the number of blocks of each type currently present in the application’s memory heap. The Overall column shows the total number of blocks of each type that were allocated, including blocks that have since been released.

Figure 1  Output from the ObjectAlloc instrument

Output from the ObjectAlloc instrumentOutput from the ObjectAlloc instrument

The histogram bars in the Allocations (Net/Overall) column give you a graphical representations of the column data. The dark portion of the bar indicates the Net value while the complete length of the bar indicates the overall value. If you see long bars and only a portion of the bar is dark, this indicates that you are allocating and releasing similar sized blocks frequently. Rather than releasing the blocks each time, you might investigate to see whether you can allocate the blocks once and reuse them later.

Clicking the checkboxes in the Graph column changes the information displayed in the track pane next to the ObjectAlloc instrument. By default, the track pane displays a running sum of the total number of bytes allocated by the application over time. You can change this setting to display the sum of allocations for one or more specific block types to see when those allocations occurred. Steep jumps in the slope of the graph indicate places where a lot of memory was allocated quickly.

In addition to display the total number of bytes allocated, you can change the type of information displayed in the track pane by changing the settings of the ObjectAlloc instrument. Clicking the information button on the instrument displays an inspector, which you can use to choose the display options for the track pane. Changing the Style field to Allocation Density shows you the number of allocations that occurred every millisecond. Spikes in this graph also indicate places where your code was allocating a lot of memory in a short amount of time.

Browsing Object Instances

The Detail pane of the ObjectAlloc instrument is where you go to find specific information about each memory allocation that was made. By default, the detail pane shows the net and overall allocations for each object type. Moving the mouse over an object type in the Category column, however, reveals an arrow button that when pressed displays details about the allocated blocks of that type. You can find out when the block was allocated along with details about the code module that allocated it.

While browsing the specific block allocations, clicking the button next to the address of a given block shows you the history of the memory allocations at that address. You can find out what type of block was allocated, when it was allocated, when it was released, who did it, and when they did it. Because allocations are tracked by address, the size and category of the block is also included. You can use this view to see all the types of data that were loaded into that particular address.

Browsing Memory By Caller

In addition to icon mode, the ObjectAlloc instrument supports an outline mode that organizes memory allocations by type and then shows the call tree that was used to make those allocations. Using this mode, you can look at how many blocks of a specific type were allocated within a given call tree of your application. In addition to viewing allocations for specific types of blocks, there is an entry for all allocations that mixes all of the memory allocations together into a single call tree, so you can see the total amount of memory allocated by your code at any given time.

You can use the outline mode to identify objects that were allocated by the same portion of code, whether directly by one of your routines or indirectly through a system routine. If you see some unexpected allocations in one of your application’s routines, you might look to see why and adjust your own memory usage accordingly. You can also use this mode to see if a particular branch of your code is allocating more memory than you expect.

Analyzing Shared Memory Usage

For Mac OS X applications, the Shared Memory instrument tracks calls to any shm_open and shm_unlink functions, which are used for opening and closing regions of shared memory in the system. You can use this information to find out where your application is getting references to shared memory regions and to examine how often those calls are being made. The detail pane displays the list of each function call along with information about the calling environment at the time of the call. Specifically, the pane lists the executable that initiated the call and the function parameters. Opening the Extended Detail pane shows the stack trace associated with the call.

Analyzing Data from the Memory Monitor Instrument

For Mac OS X applications, the Memory Monitor instrument displays assorted statistics about system memory usage. You can use this instrument to view the memory usage trends in your application or on the entire system. For example, you can see how much memory is currently active, inactive, wired, and free. You can also see the amount of memory that has been paged in or out. You might use this instrument in conjunction with other instruments to track the amount of memory your application uses with respect to specific operations.

Tracking Allocations With MallocDebug

The MallocDebug application is an alternative to the Instruments application that you can use to inspect your program’s memory allocations and look for leaks. MallocDebug shows currently allocated blocks of memory, organized by the call stack at the time of allocation. You can use MallocDebug to determine how much memory your application allocates, where it allocates that memory, and which functions allocated large amounts of memory. It gathers data from the Carbon Memory Manager, Core Foundation object allocations, Cocoa object allocations, and mallocallocations.

Like Instruments, MallocDebug does not require prior instrumentation of the program—that is, you don’t need to link with special libraries or call special functions. Instead, MallocDebug launches your application using its own instrumented version of the malloc library calls. MallocDebug does not operate on applications running on iPhone or iPod touch devices.

Note: The custom malloc library used by MallocDebug may hold on to memory blocks longer than normal for analysis purposes. As a result, you should not try to gather metrics regarding the size of your program‚Äôs memory footprint while running it under MallocDebug.

MallocDebug includes a number of features you can use to refine your memory analysis:

For information on how to use MallocDebug to identify memory leaks in your program, see “Finding Leaks With MallocDebug .”

Using MallocDebug

After launching MallocDebug, the main window appears (Figure 2). There are three basic sections in the MallocDebug window. Information about the launched program is at the top of the window. The center portion displays the call stack browser. The bottom portion displays the memory buffer browser.

Figure 2  MallocDebug main window

MallocDebug main window

To start a new MallocDebug session, you must select and launch the application you want to analyze by doing the following:

  1. Enter the full path to the program in the Executable field, or click the Browse button and select the program using the file-system browser.

  2. If you want to run the executable with command-line arguments, enter them in the Arguments field.

  3. Click the Launch button.

MallocDebug launches the program and performs an initial query about memory usage. Further updates occur whenever you press the Update button.

The Call Stack Browser

The main focus of memory analysis in MallocDebug is the call stack browser (see Figure 2). This browser shows you where memory allocations occurred by gathering stack snapshots whenever one of the malloc library routines was encountered. Figure 3 shows a sample set of data for calls to the malloc routine.

Figure 3  Function call stacks gathered at runtime

Function call stacks gathered at runtime

MallocDebug coalesces the call stack information it gathers into a call tree by overlapping equivalent sequences of functions. It then presents this information in the call stack browser. The call stack browser has three display modes: standard, inverted, and flat. Each display mode presents the data in a different way to help you identify trends. You can choose which mode you want from the left-most pop-up menu and toggle back and forth as needed.

Standard mode presents each call stack hierarchically from the function at the top of the stack (for instance, main) to the function that performs the allocation: malloc, calloc, and so on. Each element of the browser shows the amount of memory that has been allocated in the call stack involving that method or function. Figure 4 illustrates the structure of the call stack in standard mode.

Figure 4  View of function call tree in standard mode

View of function call tree in standard mode

Inverted mode reverses the hierarchy of standard mode and shows the call tree from the allocation functions to the bottom of each stack. This mode is useful for highlighting the ways in which specific allocation functions are called. By seeing all the calls to malloc or the Core Foundation allocators, you can more easily detect wasteful patterns in lower-level libraries. Use inverted mode if you’re working on a low-level framework or if you want to focus on how you’re calling malloc in your own code. Figure 5 illustrates the structure of the call stack in inverted mode.

Figure 5  View of function call tree in inverted mode

View of function call tree in inverted mode

Flat mode shows memory usage for every method and function of an application in a single list, sorted by allocated amount. All of the instances of a function call are collapsed into one browser item corresponding to that function. A function’s memory use includes the sum of all the allocations performed in that function and all allocations performed in functions that it calls. This allows you to see the total amount of memory allocated by a specific function and every function it called, not just those at the top or bottom of the call stack.

The analysis mode pop-up menu (located to the right of the viewing-mode pop-up menu) affects the type of allocations that are displayed in the call stack browser. You have several options:

Taking a Snapshot of Memory Usage

When you launch a program with MallocDebug, the main window displays the allocation activity that occurred during launch time. When you click the Update button, MallocDebug shows memory usage up to the current point in time. If you want to display allocations from a particular point in time, you can do the following:

  1. Press the Mark button.

  2. Exercise a portion of your program.

  3. Select the "Allocations from mark" item from the analysis mode pop-up list.

MallocDebug shows the buffers allocated since the mark was set. Note that MallocDebug displays only the buffers that are still currently allocated, so you will see only those buffers allocated since you clicked the Mark button that have not been freed.

Analyzing Raw Memory

When you select an allocation buffer in the call stack browser, the memory buffer list (shown in Figure 2) might show one or more lines of data. Each line in this list represents a block of memory allocated by the currently selected function or by a function eventually called by that function. Each line contains the address of the buffer, its size (in bytes), and the zone in which it was allocated. Double-clicking one of these lines opens the Memory Viewer Panel window, which you can use to inspect the contents of memory at that location.

If code attempts to write before the start or past the end of a buffer, the memory buffer list shows an appropriate indicator in the Status column. If bytes were written before the buffer, the column displays a less-than < character. If bytes were written after the buffer, the column contains a greater-than > character. Use the popup menu below the list to sort the list contents.

MallocDebug helps you catch some types of problems by writing certain hexadecimal patterns into the hex values displayed in the Memory Viewer Panel window. It overwrites freed memory with 0X55 and it guards against writing beyond a block’s boundaries by putting the values 0xDEADBEEF and 0xBEEFDEAD, respectively, at the beginning and end of each allocated buffer.

The memory buffer inspector can be particularly helpful for determining why an object is leaking. For example, if a string is being leaked, the text of the string might indicate where it was created. If an event structure is leaked, you might be able to identify the type of event from the contents of memory and thus find the corresponding event-handling code responsible for the leak.

Evaluating MallocDebug Problem Reports

Some of the reports that MallocDebug presents identify obvious problems that you should fix immediately. Some of these problems include leaks, buffer overruns, and references to freed memory. Other problems are more subjective in nature and require you to make a determination as to whether there is a problem.

To improve your program’s overall allocation behavior, use MallocDebug’s detailed accounting of memory usage to explore the memory usage of your program. This can help you identify wasted memory allocations or unexpected allocation patterns and thus optimize your program’s memory usage. As you analyze your memory allocations, consider the following items:

Limitations of MallocDebug

You can use MallocDebug to gather data for applications running in Mac OS X only. The following section describes some of the other issues you may run into when running MallocDebug.

Allocated Memory Reporting

MallocDebug shows the current amount of allocated memory at a given point in a program’s execution; it does not show the total amount of memory allocated by the program during its entire span of execution. Memory that has been freed is not shown.

To see memory that your program has allocated and freed, use the malloc_history tool. See “Tracking Memory Allocations With malloc_history” for more information.

Crashing Under MallocDebug

If a program crashes under MallocDebug, a diagnostic message is printed to the console that explains why the program crashed. Listing 1 gives an example of MallocDebug’s crash diagnostic message.

Listing 1  Diagnostic output from crashing under MallocDebug

MallocDebug: Target application attempted to read address 0x55555555, which can’t be read.
MallocDebug: MallocDebug trashes freed memory with the value 0x55,
MallocDebug: strongly suggesting the application or a library is referencing
MallocDebug: memory it already freed.
MallocDebug: MallocDebug can’t do anything about this, so the app’s just going to have to be terminated.
MallocDebug: libMallocDebug cannot help the application recover from this error,
MallocDebug: so we’ll just have to shut down the application.
MallocDebug: *************************************************
MallocDebug: THIS IS A BUG IN THE PROGRAM BEING RUN UNDER MALLOC DEBUG,
MallocDebug: NOT A BUG IN MALLOC DEBUG!
MallocDebug: *************************************************

Usually a crash results from subtle memory problems, such as referencing freed memory or dereferencing pointers found outside an allocated buffer. Check suspected buffers of memory with the memory-buffer inspector (see “Analyzing Raw Memory”). If your program is referencing memory at 0x55555555, then it is referencing freed memory.

Important: You should always investigate and fix bugs that cause your program to crash. Subtle problems may indicate a design flaw that could cost more time to fix later.

Programs Calling setuid or setgid

For security reasons, the operating system does not allow programs running setuid (set the user id at execution) or setgid (set the group id at execution) to load new libraries, such as the heap debugging library used by MallocDebug. As a result, MallocDebug cannot display information about these programs unless they are run by the target user or by a member of the target group.

If you want to examine a setuid or setgid program with MallocDebug, you have two options:

Running Under libMallocDebug

If you’re writing a simple program that runs from the command-line, you may need to statically link the malloc routines into your executable before MallocDebug can attach to your program. Most programs link to the System framework, which is instrumented for use by MallocDebug. If your program does not use this framework, you can explicitly link your program with the /usr/lib/libMallocDebug.a library. (If you are running in Mac OS X 10.3.9 or later, you can also execute the command set env DYLD_INSERT_LIBRARIES /usr/lib/libMallocDebug.A.dylib from the debugger console to attach your program to libMallocDebug.) You should not notice any difference in your program’s allocation behavior when linking with this library.

If you do link your application to libMallocDebug, you should be aware of the following caveats:

Setting Environment Variables

MallocDebug does not contain any built-in mechanism for setting environment variables. You can work around this limitation by setting your environment variables from Terminal and then launching MallocDebug from there. When launched in this manner, your application inherits the Terminal environment, including any environment variables.

Do not launch MallocDebug from Terminal using the open command. Instead, run the MallocDebug executable directly. The executable is located in the MallocDebug.app application bundle, usually in the MallocDebug.app/Contents/MacOS directory.

Tracking Memory Allocations With malloc_history

In Mac OS X, the malloc_history tool displays backtrace data showing exactly where your program made calls to the malloc and free functions. If you specify an address when calling malloc_history, the tool tracks memory allocations occurring at that address only. If you specify the -all_by_size or -all_by_count options, the tool displays all allocations, grouping frequent allocations together.

Before using the malloc_history tool on your program, you must first enable the malloc library logging features by setting the MallocStackLogging to 1. You may also want to set the MallocStackLoggingNoCompact environment variable to retain information about freed blocks. For more information on these variables, see “Enabling the Malloc Debugging Features.”

The malloc_history tool is best used in situations where you need to find the previous owner of a block of memory. If you determine that a particular data is somehow becoming corrupted, you can put checks into your code to print the address of the block when the corruption occurs. You can then use malloc_history to find out who owns the block and identify any stale pointers.

The malloc_history tool is also suited for situations where Sampler or MallocDebug cannot be used. For example, you might use this tool from a remote computer or in situations where you want a minimal impact on the behavior of your program.

For more information on using the malloc_history tool, see malloc_history man page.

Examining Memory With the heap Tool

In Mac OS X, the heap command-line tool displays a snapshot of the memory allocated by the malloc library and located in the address space of a specified process. For Cocoa applications, this tool identifies Objective-C objects by name. For both memory blocks and objects, the tool organizes the information by heap, showing all items in the same heap together.

The heap tool provides much of the same information as the ObjectAlloc instrument, but does so in a much less intrusive manner. You can use this tool from a remote session or in situations where the use of Instruments might slow the system down enough to affect the resulting output.

For more information about using the heap tool, see heap(1) man page.




Last updated: 2008-07-02

Did this document help you? Yes It's good, but... Not helpful...