< Previous PageNext Page > Hide TOC

Examining Memory Allocation Patterns

Examining your application’s memory allocation patterns can help reveal algorithms that may not be the most efficient in their memory use. If you see a large number of allocations occurring during a loop, you may decide to go back and change the allocations to occur outside of the loop. This kind of reduction can have a significant increase in application performance.

Apple provides several tools for examining your memory usage. The MallocDebug tracks the location of memory allocations by recording the application call stack whenever a memory-related function is called. The malloc_history tool does many of the same things as MallocDebug but from a command-line interface. You can use these tools to look for unexpectedly large allocations or allocations that were made but are no longer needed.

If you are writing a Cocoa application, you should use the ObjectAlloc program and heap tool to see which Objective-C objects your program creates. The ObjectAlloc program is good for finding problems involving allocation trends, retain/release problems, or other problems involving object allocations. Similarly, the heap tool helps you examine the objects currently in use by a program.

Contents:

Debugging Allocations With MallocDebug
Tracking Memory Allocations With malloc_history
Observing Allocations With ObjectAlloc
Examining Heaps With the heap Tool


Debugging Allocations With MallocDebug

The MallocDebug application provides tools for inspecting your program’s memory use and for finding memory 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.

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.

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 Memory Leaks.”

Using MallocDebug

After launching MallocDebug, the main window appears (Figure 1). 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 1  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 1). This browser shows you where memory allocations occurred by gathering stack snapshots whenever one of the malloc library routines was encountered. Figure 2 shows a sample set of data for calls to the malloc routine.


Figure 2  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 3 illustrates the structure of the call stack in standard mode.


Figure 3  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 4 illustrates the structure of the call stack in inverted mode.


Figure 4  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 1) 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

The following section describes some of the 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 Terminal 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

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 malloc_history, see the man pages.

Observing Allocations With ObjectAlloc

ObjectAlloc allows you to observe memory allocation activity in an application. It shows you the allocations in terms of the number of objects created, rather than where the allocations occurred. Its real-time histograms allow you to directly perceive changes and trends in object counts. It also retains a history of allocations and deallocations, allowing you to identify overall allocation trends.

The information displayed by ObjectAlloc 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 are recorded.

Using ObjectAlloc

When you first launch ObjectAlloc, it asks you to choose the application you want to inspect. After selecting the application, ObjectAlloc displays the main window so that you can launch the application and start gathering data. The main window contains several buttons for controlling the launch and execution of the application, as well as for setting mark points from which to examine data. Figure 5 shows the ObjectAlloc main window.


Figure 5  ObjectAlloc window

ObjectAlloc window

When you click the Start button, ObjectAlloc launches the application and starts displaying object allocation data as it occurs. You can use the buttons along the top of the window to control the gathering and display of collection data. If you want to view past allocations, you must pause or stop the data gathering process before using the controls to step forward or backward through the allocation history. You can use the slider control just under the buttons to watch changes in allocation counts over time.

The Mark button sets a starting point from which to watch allocations. This starting point is a convenience that lets you view allocations over a more recent period of time. Use the “Show since mark” checkbox to toggle between displaying events that occurred since the mark was set and displaying events that occurred since the application was launched.

Note: Due to the sheer quantity of information being processed, updating the ObjectAlloc main window can slow the system down noticeably. Uncheck the “Live update” checkbox to update the display only when the ObjectAlloc window is activated or deactivated.

Browsing Global Allocations

The Global Allocations tab contains a table with a listing of all memory blocks ever allocated in the application. 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 Current column shows the number of blocks of each type allocated but not (yet) released. The Peak column shows the largest number of blocks of each type that existed at any given time. The Total column shows the total number of blocks of each type that have been allocated, including blocks that have since been released.

The histogram bars to the right of the Total column are graphical representations of the three columns: the dark portion of the bar indicates the Current value, the middle portion of the bar is the additional number under Peak, and the complete length of the bar indicates the value under Total. The Scale slider controls the number of objects represented by each pixel in a bar (the actual number is shown to the right of the bar).

The “Counts are bytes” checkbox changes the numbers in the Current, Peak, and Total columns to reflect the number of bytes allocated (per object type) instead of the number of objects allocated (per object type).

Browsing Object Instances

The Instance Browser tab lists each type of block. Clicking a block type displays a list of all instances of that block. Clicking the address of a block instance displays a list of all allocation events pertaining to that block, including allocation, retain, release, autorelease, and free events. If the block has not yet been freed, the contents of the block are displayed in the bottom pane of the ObjectAlloc window. Clicking an event brings up a textual description of the event, including a function call stack.

Browsing Call Stacks

The Call Stacks tab displays a table of each block type along with the number of instances (Count) and the number of bytes allocated to those instances (Size). The furthest-right column of this table contains the first item of a hierarchical function call tree. Clicking the disclosure triangle displays the next level of the function call stack. When the function call stack is open, it displays the location of each allocation.

The Descend Unique Path button discloses the selected function call stack to the deepest function shared by each instance’s function call stack. The Descend Max Path button discloses the selected function call stack to the deepest function in the stack.

Interpreting ObjectAlloc Data

Here are some general guidelines for interpreting the data reported by ObjectAlloc:

Examining Heaps With the heap Tool

The heap 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 application, 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 ObjectAlloc might slow the system down enough to affect the resulting output.



< Previous PageNext Page > Hide TOC


© 2003, 2006 Apple Computer, Inc. All Rights Reserved. (Last updated: 2006-06-28)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.