TweetFollow Us on Twitter

TidyHeap

Volume Number: 13 (1997)
Issue Number: 5
Column Tag: develop

Squashing Memory Leaks With TidyHeap

by Mike Fullerton

One of the more mundane aspects of application development is making sure any system resources that your application allocates get deallocated, particularly memory allocations. Think of the hours you've spent tracking down pesky memory leaks. A powerful debugging and QA tool, TidyHeap watches over memory allocations and helps you track down leaky blocks. Learn how to make sure that memory allocated by your application is always managed correctly.

TidyHeap is a tool for tracking and verifying dynamically allocated memory in C++ applications. It started out as a quick and dirty way to keep track of undeleted objects in the MacApp framework and evolved into a tool for anyone writing application software in C++. TidyHeap works with any application built in C++, with or without a framework. Among its powerful features are the following:

  • If your application allocates an object or data that's never deleted, TidyHeap tells you about it when your application quits. (Objects and data allocated by your application are called client objects in this article.)
  • TidyHeap can provide you with the filename and line number where any existing client object was created, including a client object that's never deleted.
  • You can tell TidyHeap to watch for double deletions on all client objects or on a specific client object.
  • You can verify the integrity of a single client object or all client objects at each pass through the event loop.
  • You can have TidyHeap break into MacsBug when a specific client object is deleted.
  • You can force every single new operation to fail in consecutive order, in consecutive runs of your application.
  • You can design your own tests for specific client objects or for all client objects.

In short, TidyHeap is designed to be flexible, powerful, and user extensible. Currently, TidyHeap runs only on the PowerPC(tm) platform (if you would like to see it implemented for 680x0 machines, send e-mail to mabugs@devtools.apple.com), and it's compatible only with Metrowerks CodeWarrior (we MacAppsters plan to make it compatible with the various MPW compilers sometime soon). A package of TidyHeap materials is available at www.mactech.com.

TidyHeap Basics

TidyHeap itself is a small library of C++ classes that intercept and track all allocations and deallocations performed by the global operators new and delete. It does this invisibly - you don't need to do anything but call new and delete in the way you usually do. Also, since TidyHeap is essentially a debugging tool, it's compiled and enabled only if its preprocessor constant qTidyHeap is defined to true. This enables you to turn it off easily when building nondebug versions of your application.

TidyHeap works with any data type that can be created with new. This can be all the objects in your application or framework, structs created to be passed to Toolbox routines, or huge char arrays created as buffers. It really doesn't matter. TidyHeap treats all allocations as raw blocks of allocated memory, without knowing or caring what the user data is.

The raw materials

TidyHeap ships with two CodeWarrior projects and every source file needed to build and use it. The projects are for building the shared library, TidyHeapSharedLib, and the static library, TidyHeapPPC_d. Both libraries are required because TidyHeapSharedLib doesn't contain TidyHeap itself, but is the mechanism I use to make sure that TidyHeap is the last thing to be deleted, after static destruction time.

It's essential that TidyHeap be the very last thing deleted when the client application quits. This guarantees that the application won't try to delete anything after TidyHeap, which could cause TidyHeap to return inaccurate information. To make sure that it terminates after static destruction time, TidyHeap registers a callback in TidyHeapSharedLib that's called when the shared library terminates. It so happens that this occurs after static destruction time, which ensures that TidyHeap is the very last thing deleted.

You may build the shared library if you need to; however, a built version of TidyHeapSharedLib is also included. Install this as you would any shared library, either in the same folder as the application or in your Extensions folder - just be careful not to install it in both places. Also, don't forget to add TidyHeapSharedLib to your application's project! At this time weak importing of the shared library is not supported, so don't use weak linking. If you do, your application may crash.

The second CodeWarrior project is for TidyHeap itself. There are about 35 source files. You can include them directly in your application's project or you can build them into a static library with the TidyHeapPPC_d.n project and include the static library in your project. The choice is yours. Personally, I prefer building TidyHeap as a library.

Finally, TidyHeap ships with two small tools - New Dropper and TidyHeap Director. New Dropper allows you to easily insert into or remove from your source files an important macro, and TidyHeap Director lets you change TidyHeap's behavior without recompiling your code. These tools aren't yet fully supported by Apple (so use them at your own risk), but they're very useful - as you'll see later.

Hooking in your framework or project

Hooking into TidyHeap is simple. You define a C function named .TidyHeap declares and calls the function but doesn't define it.

(If this function isn't defined, you'll get a link error.) defines the global operators new and delete that TidyHeap calls, and allocates AC_CTidyHeap or a client-defined subclass of TidyHeap. (See "MacApp Naming Changes" for the reasons behind TidyHeap's naming conventions.)

TidyHeap has static pointers to the global operators new and delete. By default, the static pointers point to NewPtr and DisposePtr. These are the functions that TidyHeap calls to actually create and delete memory blocks. The function must set the proper memory allocation and deallocation functions for your framework before it creates AC_CTidyHeap or its subclass. For example, the following code defines for the MacApp framework in which MAOperatorNew and MAOperatorDelete are MacApp memory allocation and deallocation hooks. (Although this and later examples use MacApp, don't forget that TidyHeap works with any framework.)

AC_CTidyHeap* CreateTidyHeap()
{
 AC_CTidyHeap::GlobalNew = MAOperatorNew;
 AC_CTidyHeap::GlobalDelete = MAOperatorDelete;
 return TH_new TMacAppTidyHeap();
}

The AC_CTidyHeap class includes virtual functions that you can override if you want to change TidyHeap's behavior. For example, the method HandleNilAllocation is called by TidyHeap when it forces new to fail. If your framework throws an exception when new fails, you can override HandleNilAllocation to throw the same exception. This enables TidyHeap to properly emulate what happens when new fails in your environment. (More on forcing new to fail later.)

To use the default TidyHeap and the default memory allocation hooks, include the file CreateDefaultTidyHeap_AC.cp, which defines a function that uses the defaults:

AC_CTidyHeap* CreateTidyHeap()
{
 return new AC_CTidyHeap;
}

Now you're ready to use TidyHeap and begin reducing those hours spent tracking memory leaks.

First contact

In this section you'll meet the headers and trailers, the AC_CTidyHeapBlock object, and the TH_new macro, all of which TidyHeap uses to track and store data it needs to watch over your memory allocations and perform various actions.

TidyHeap itself is a single object that's created when the global operator new or the AC_CTidyHeap static member function Instance is called for the first time. Instance returns a pointer to the AC_CTidyHeap object. If this object hasn't been allocated yet, Instance creates it and returns the pointer. In this way you're guaranteed to have a valid pointer to the AC_CTidyHeap object. You can use Instance to call AC_CTidyHeap's interface. For example, the following line of code returns the total amount of memory currently allocated by your application using the new operator.

long sizeTally = AC_CTidyHeap::Instance()->GetSizeTally();

Header and trailers

When your application calls new to allocate a client object, TidyHeap intercepts the call and increases the amount of memory allocated by a small amount in order to put a header and trailer around the client object's memory block. TidyHeap stores data in the header and trailer that allows it to track your client object. The header contains a pointer to an AC_CTidyHeapBlock object, which has been allocated by TidyHeap and stored in a linked list. This is how TidyHeap tracks all the client objects. Every client object allocated with new has its own AC_CTidyHeapBlock object (described in the next section).

The header and trailer also contain three markers. Markers are long integers that TidyHeap sets to magic values you can easily recognize when looking at a raw memory dump of your object - 0xF1F1F1F1, 0xF2F2F2F2, and 0xF3F3F3F3. These markers act as fences around your client object (TidyHeap operates on the assumption that if the markers get trashed your client object is probably trashed also). TidyHeap can quickly verify the integrity of your block of data by checking the markers. There are two markers in the header, one just before and one just after the pointer to the client object's AC_CTidyHeapBlock object, and one marker in the trailer, as shown in Figure 1.

AC_CTidyHeapBlock and block IDs

The AC_CTidyHeapBlock class is important. An AC_CTidyHeapBlock object holds information about the client object your application allocated, and member functions defined for the class are used to perform various operations on the client object.

Your client object's block ID is one of the more useful pieces of information you can obtain from AC_CTidyHeapBlock. The block ID is a unique number assigned by TidyHeap to each client object that's created with new. The block ID corresponds to the number of times new has been called, so if the block ID is 6, the client object was created on the sixth call to new. Here's an example of how to get the block ID from a client object:

TClientObject* myObject = new TClientObject;
AC_CTidyHeapBlock* objBlock = AC_CTidyHeap::Instance()->GetBlock(myObject);
long blockId = objBlock->GetID();

Among the member functions defined for the AC_CTidyHeapBlock class is the Verify method. By first getting the pointer to its AC_CTidyHeapBlock object and then calling AC_CTidyHeapBlock::Verify, you can verify the integrity of your client object. The Verify method cross-references the pointer to the client object's AC_CTidyHeapBlock object that the client object stores in its header with the pointer to its client object that the AC_CTidyHeapBlock object stores. It also checks the validity of the block's markers. For example, if you write past the end of your object, the trailer marker will be invalid and TidyHeap will notify you by returning an error from Verify. Here's an example of using the Verify method:

TClientObject* myObject = new TClientObject;
AC_CTidyHeapBlock* objBlock = AC_CTidyHeap::Instance()->GetBlock(myObject);
AC_CTidyHeapError err = objBlock->Verify();

Storing filename and line number with TH_new

TidyHeap provides TH_new, an optional macro replacement for the global operator new. TH_new stores the filename and line number of where the client object was created in the client object's AC_CTidyHeapBlock object. The filename and line number enable you to find the code that created undeleted client objects. TH_new uses the C++ preprocessor's built-in __FILE__ and __LINE__ macros, which is why TH_new needed to be a macro. Of course, you don't want to ship your application with TidyHeap enabled, so TH_new resolves to new when qTidyHeap is not defined or is defined to false, making it possible to leave the TH_new macro in your shipping code.

Listing 1. Getting the filename and line number
void main()
{
 TClientObject* myObject = TH_new TClientObject;
 AC_CTidyHeapBlock* objBlock = 
 AC_CTidyHeap::Instance()->GetBlock(myObject);
 const char* fileNamePtr = objBlock->GetFileName();
 long lineNum = objBlock->GetLineNum();
 printf("MyObject was created in file: %s at line #%ld\n", 
 fileNamePtr, lineNum);
}

Listing 1 shows how to get a filename and line number for an object created with TH_new. When the program is run, you get the following output:

MyObject was created in file: Main.cp at line #1

The New Dropper tool that ships with TidyHeap makes it easy to switch between new and TH_new. Drag your project's folder onto the New Dropper tool and you're presented with two options: change TH_new to new or change new to TH_new. That's it. When you make a choice, New Dropper scans the source files you dropped on it and makes the chosen change. New Dropper finds all the source files in all the folders, no matter how deeply you've nested them. It only opens files that it decides are text files with source code in them. In other words, it won't open your project files, or even a text file that doesn't have a ".h" or ".cp" appended to its name. It doesn't change new in comments, in object-specific overrides of the new operator in a client object, or if the file has "TidyHeap" anywhere in its name. The software is provided as is, so please make a backup of your source before using it!

Warnings, logging, and the log file

TidyHeap has two types of messages - a logged message and a warning - and provides a default mechanism for directing logged messages to a log file. The log file is written to the same folder as your application and is named myapplication.log. It's an MPW text file and is compatible with MPW scripting. The AC_CTidyHeap method you can use to log a string is

AC_CTidyHeap::Logf(const char*, ...);

All the output from Logf is appended to the log file, and it's designed to be compatible with the ANSI-standard printf. Here's some code showing how you could use Logf:

TClientObject* myObject = TH_new TClientObject;
AC_CTidyHeapBlock* objBlock = AC_CTidyHeap::Instance()->GetBlock(myObject);
AC_CTidyHeap::Instance()->Logf("The object I just created has an ID of 
%ld",
 objBlock->GetID());

The warning mechanism is simply a wrapper on top of DebugStr that can be turned on and off. You'll get a TidyHeap warning in only a few situations - in general, to notify you that something has gone wrong. For example, if your application terminates and there are five client objects that haven't been deleted, you'll get the warning "TidyHeap Warning: You have 5 undeleted blocks."

This undeleted-block warning has a g appended to it so that your application will continue immediately after dropping into MacsBug. I think you'll like it better than typing g and Return a thousand times.

The AC_CTidyHeap method that you use to send a warning is

AC_CTidyHeap::Warnf(const char*, ...);

Like Logf, it behaves the same way as the ANSI printf, except that the output goes to MacsBug, of course.

When you get a warning, TidyHeap usually logs more information about the problem to the log file, which is described next.

Listing 2. Leaving undeleted objects
#include "UClientObject.h"
#include "CTidyHeap_AC.h"
void main()
{
 TClientObject* object1 = TH_new TClientObject;
 TClientObject* object2 = new TClientObject;
 TClientObject* object3 = TH_new TClientObject;
 
 delete object3;
}

Using the log file

Let's see how to use the log file to track down memory leaks. For example, after running the program in Listing 2, you'll get this warning from TidyHeap: "TidyHeap Warning: You have 2 undeleted blocks." When there are undeleted client objects after your application quits, TidyHeap logs information about all the objects that haven't been deleted to the log file.

Here's what the log file looks like after you run the program in Listing 2:

### TidyHeap Termination Messages:
### 2 Outstanding blocks, 3 total blocks, Ave Size 4.500000
### New called 3 times, Delete called 1 times
### BlockInfo: ID:1, Address:0x1EC8F8C, Size:4
 File 'Main.cp'; Line 6
### BlockInfo: ID:2, Address:0x1EC902C, Size:4
 File 'unknown'; Line 0
### Sum of outstanding block sizes = 8 bytes

The log file contains some useful information, as you can see. There are two outstanding blocks - the two TClientObject objects that the program in Listing 2 neglected to delete. The new operator was called three times, and delete was called once, which jibes with what we know from the example code.

Because object1 was created by the TH_new macro, you can see exactly where it was created and go back and make sure it gets deleted - a piece of cake, even on huge projects.

Unfortunately, we didn't use TH_new for object2, so TidyHeap logged its location as "unknown." However, you can tell which object it was by looking at its block ID. The object has a block ID of 2 (### BlockInfo: ID:2), which means it was created second. In the case of this example program, it's trivial to figure out which object was created second. It's not so trivial to locate the client object that has a block ID of 1,233 in a two million-line project. Later, I'll show you a couple of advanced techniques for tracking down a block when all you have is its block ID.

Actions

With actions you can modify TidyHeap's behavior, the AC_CTidyHeapBlock object, or the client object that's being operated on currently. Actions are lightweight subclasses of AC_CTidyHeapAction. TidyHeap's action class architecture makes it easy to customize and add features to TidyHeap. Read on to learn how to install actions, use the actions that ship with TidyHeap, and create your own actions.

Installing into global and object contexts

Action objects are differentiated by their context. There are two types of context: global and object. An action that's executed in a global context operates on all allocated objects, while an action that's executed in an object context operates on only a single object.

TidyHeap manages two different lists of actions that operate in the global context - the global new and global delete actions. When a global new action is installed, it's performed on every block of memory that's processed through new; a global delete action is performed on every block of memory processed through delete.

For example, AC_CActionVerifyBlock is one of the action classes that ship with TidyHeap. When an AC_CActionVerifyBlock action is installed as a global delete action, every block of memory is verified as it's being deleted. You would install an AC_CActionVerifyBlock action as a global delete action as follows:

AC_CActionVerifyBlock* theAction = TH_new     AC_CActionVerifyBlock;
AC_CTidyHeap::Instance()->AcquireDeleteAction(theAction);

Here's the code to install AC_CActionVerifyBlock as a global new action:

AC_CTidyHeap::Instance()->AcquireNewAction(theAction);

All actions, once they're installed, are deleted automatically at the appropriate time by TidyHeap. The method names start with "Acquire" to make it clear that TidyHeap owns the installed action.

When installing an action into an object context, you can install it only as a delete action. You do this by getting the pointer to the client object's AC_CTidyHeapBlock object, and then calling the AC_CTidyHeapBlock class's AcquireDeleteAction method. Once an action is installed in an object context, it will be performed once as the client object is being deleted.

Listing 3 shows how to install an AC_CActionBreakOnDelete action. This action calls DebugStr to break the program into MacsBug when the client object is deleted. AC_CActionBreakOnDelete provides an alternate method for tracking down leaks. If you install this action in a client object that you're suspicious of, and your program never gets the appropriate MacsBug message, you know the client object has leaked. The MacsBug message you would get from the program in Listing 3 when the block is deleted is "Deleting Block 1."

You don't have to use TH_new when creating AC_CTidyHeapAction classes. TidyHeap's objects are tracked differently from client objects so that none of the TidyHeap classes will show up as undeleted blocks.

Listing 3. Installing AC_CActionBreakOnDelete
#include "CTidyHeapActions_AC.h"
void main()
{
 TClientObject* myObject = TH_new TClientObject;
 AC_CTidyHeapBlock* objBlock = 
 AC_CTidyHeap::Instance()->GetBlock(myObject);
 AC_CActionBreakOnDelete* theAction = TH_new AC_CActionBreakOnDelete;
 objBlock->AcquireDeleteAction(theAction);
 delete myObject;
}

Built-in action classes

TidyHeap ships with a handful of action classes. You can use some of these action classes in more than one context. For example, as shown in the previous section, you can use AC_CActionVerifyBlock as a global delete action, but there's no reason why you can't also use it as a delete action assigned to a specific object. Just be sure to allocate a new action object for each context you install the action in.

AC_CActionBreakOnDelete and AC_CActionVerifyBlock are described in the previous section. The remaining built-in action classes are described below.

AC_CActionBreakOnNew

In the section "Warnings, Logging, and the Log File" I pointed out that it can be extremely difficult to locate a client object when all you have is the block ID. The action class AC_CActionBreakOnNew helps you do this. You can install an AC_CActionBreakOnNew object as a global new action. AC_CActionBreakOnNew takes a long integer as a parameter in its constructor; this parameter represents a block ID. When the client object with the given ID is allocated with new, the action will break into MacsBug. At this point you can do a stack crawl in your favorite debugger. Here's an example where you're trying to track down the client object with the block ID 1042:

AC_CActionBreakOnNew* theAction = TH_new AC_CActionBreakOnNew(1042);
AC_CTidyHeap::Instance()->AcquireNewAction(theAction);

Another way to locate a client object with a block ID is by using the block ID to set a conditional breakpoint in your debugger deep in the guts of TidyHeap. For example, set it on the line in CTidyHeap_AC.cp that increments the counter in the method CreateBlock (currently line 287, blockPtr->fId = fCount). AC_CTidyHeap::CreateBlock allocates the memory for client objects' AC_CTidyHeapBlock objects.

AC_CActionMakeNewFail

The action class AC_CActionMakeNewFail does what its name implies - it takes a long integer n as a constructor parameter that tells the action to make calls to new fail on the nth call. Install an AC_CActionMakeNewFail action as a global new action.

AC_CActionVerifyAll

An AC_CActionVerifyAll action iterates through the list of currently allocated client objects and verifies them all, one at a time. TidyHeap warns you if it finds a corrupt object. Be warned that this significantly slows down your application if installed in a global context. You can use the action class AC_CActionVerifyAll in either of the action contexts.

AC_CActionDoubleDeleteWatcher

The action class is particularly useful. An AC_CActionDoubleDeleteWatcher action marks the client objects sent into delete as deleted, but prevents the memory allocated for the client object from actually being deleted. If the object is deleted a second time, TidyHeap will catch it. The downside to installing AC_CActionDoubleDeleteWatcher is that objects being watched are never actually deleted. If you're having problems with a client object being deleted multiple times, I recommend cranking up your application's memory partition and running with AC_CActionDoubleDeleteWatcher installed. It will catch the double deletion as soon as it occurs. You can install an AC_CActionDoubleDeleteWatcher action either as a global delete action or in a specific client object.

Even when an AC_CActionDoubleDeleteWatcher action isn't installed, TidyHeap still looks out for double deletions. Every client object that's deleted is marked, and if it comes through delete again, TidyHeap catches it if possible. The trouble is that in normal operating circumstances, the second time through, the object pointer is pointing at invalid memory, so the "already deleted" mark may not be valid - anything could be occupying that memory. However, in my experience, double deletions usually happen within a very short time of each other, so you have a decent chance of finding the memory still undisturbed. As long as memory is undisturbed, TidyHeap catches the second deletion.

AC_CActionVerifyBlock may catch a double deletion if it's installed as a delete action, because the memory the client object originally occupied may be overwritten, in which case the markers will probably be invalid and you'll get a corrupted-object warning.

AC_CActionExemptBlocks

I added the action AC_CActionExemptBlocks so that it would be possible to tell TidyHeap to ignore certain objects. For example, there are a few objects that MacApp Release 12 creates during startup that are not deleted (this was done to optimize quit times). To ensure that TidyHeap's undeleted-block messages are accurate, you can exempt those blocks. Install the AC_CActionExemptBlocks action as a global new action. Listing 4 shows the code to do this (the code is taken from the sample application Skeleton that ships with MacApp).

Listing 4. Exempting blocks
void main()
{
 // Here's where the client objects we want to exempt are created,
 // so install the action.
 AC_CTidyHeapAction* action = new AC_CActionExemptBlocks;
 AC_CTidyHeap::Instance()->AcquireNewAction(action);

 InitUMacApp(4);
 InitUPrinting();
 InitUViewSkeleton();
 
 // Now we want to start tracking objects, so remove the exempter.
 AC_CTidyHeap::Instance()->RemoveNewAction(action); 

 // RemoveNewAction doesn't delete the action, so we do it ourselves.
 delete action;

 TApplicationSkeleton* aApplicationSkeleton = 
 new TApplicationSkeleton;
 aApplicationSkeleton->IApplicationSkeleton();
 aApplicationSkeleton->Run();
}

AC_CActionGarbageIn and AC_CActionGarbageOut

The AC_CActionGarbageIn and AC_CActionGarbageOut actions fill the client object's memory with garbage values just after allocation and just before deletion, respectively. The values are defined in the objects' class definitions as kGarbageInValue (0xF5) and kGarbageOutValue (0xF6). The values are meant to be recognizable and to cause a bus error if dereferenced. Install AC_CActionGarbageIn as a global new action. You can install AC_CActionGarbageOut either as a global delete action or in a specific client object.

AC_CActionExemptUnknownBlocks

With the AC_CActionExemptUnknownBlocks action installed, TidyHeap only tracks objects created with TH_new. This is handy for times when you have a lot of undeleted blocks and want to debug those created with TH_new separately. I used this action when working with MacApp Release 12, which, as I noted above, deliberately doesn't delete some blocks that were created at startup time. It worked like a charm! Install AC_CActionExemptUnknownBlocks as a global new action.

AC_CActionIncrementalNewFailer

The AC_CActionIncrementalNewFailer action is specially designed for you QA folks to make your engineers' lives miserable. AC_CActionIncrementalNewFailer makes new fail sequentially - first new number one fails, then number two fails, then number three, and so on. The kicker is that TidyHeap saves the count into a text file so that the next new that will fail is persistent between runs of your application. This stresses your failure-handling code to the limit! Install this action as a global new action.

Rolling your own action classes

The AC_CTidyHeapAction class is a very simple and lightweight class. To make your own action class, simply subclass AC_CTidyHeapAction and override the pure virtual function DoAction. The function takes as a parameter a pointer to an AC_CTidyHeapBlock object, which is the object TidyHeap is currently operating on. Listing 5 shows the code overriding DoAction for the AC_CActionBreakOnNew action class.

Listing 5. AC_CActionBreakOnNew::DoAction
void AC_CActionBreakOnNew::DoAction(AC_CTidyHeapBlock* inBlock)
{
 if (inBlock->GetID() == fID) {
 char str[80];
 ::sprintf(str, "AC_CActionBreakOnNew: Block ID: %ld", fID);
 ::c2pstr(str);
 
 ::DebugStr((StringPtr) str);
 }
}

Changing Settings with Tidyheap Director

TidyHeap writes its current settings to a file named myapplication.prf in your application's folder. It saves to this file any changes to TidyHeap settings made between runs of your application so that you can use the TidyHeap Director tool to edit the file and change the behavior of TidyHeap without recompiling your code.

Figure 2 shows the TidyHeap Settings File dialog box. The application you're working with appears after "Target Application." On the left are five Features preferences.

• Check Enabled to turn TidyHeap on; unchecking this option effectively turns off TidyHeap completely.

• Check Warnings to send warnings to MacsBug.

• If Warnings is enabled, you can set Undeleted Blocks, which causes TidyHeap to send a list of undeleted blocks to MacsBug when your application terminates.

• Check Log Undeleted Blocks to enable logging of undeleted blocks to the log file (see the section "Using the Log File"). If you have many undeleted blocks, the logging process can take a while and you may want to shut off the logging.

• Check Pointers Live Only in App Heap to tell TidyHeap to verify that pointers you send into GetBlock or VerifyBlock are within your application's memory heap.

Use the checkboxes under Global New and Global Delete to automatically install the listed actions as global new or delete actions when TidyHeap starts up.

The settings file is read once - when TidyHeap is created. To make changes to your settings, make sure your application isn't running at the time. The next time your application is run, your new settings will be loaded.

Alternative to TidyHeap

There are other tools with features similar to TidyHeap. This section tells you a little about some of them and compares them with TidyHeap.

Metrowerks ships a tool called DebugNew. You'll find the library and a demo for DebugNew on the CodeWarrior CDs. DebugNew has some of the same features as TidyHeap, but it's not as extensible and doesn't have as many features. The features it does have are quite valuable, however: it can check for leaks, validate blocks of allocated memory, and verify that a block is in the application heap. DebugNew also has a macro like TH_new called NEW, and it has a log file. DebugNew is smaller than TidyHeap and is written in C, so it may run in a smaller footprint and it doesn't require C++.

Another tool for tracking memory leaks is the ZoneRanger application, also from Metrowerks. ZoneRanger is quite good not only at tracking memory leaks, but also at fine-tuning your application's heap and managing memory. This is a great tool that every programmer should have at hand.

QC and Spotlight by Onyx Technology are MacOS system extensions that provide memory debugging for applications without requiring that you modify the source code or recompile the application. QC stress tests applications for all kinds of memory-related errors. These tools work well with applications that directly allocate memory with the Macintosh Memory Manager or that manage resources returned by the Resource Manager, and can be used in conjunction with TidyHeap.

Memory Mine by Adianta is a standalone tool for monitoring heaps and stress testing applications. It flags heap corruption when it happens and you can see memory leaks as they occur. Source code is not needed to monitor heaps.

Apple ships a handful of dcmds (debugger commands for MacsBug) that are extremely helpful as well: Blat makes sure that nobody writes to the first 256 bytes of low memory, DisposeResource catches resource handles that are passed to DisposeHandle, Leaks watches for memory leaks when you tell it to (via "leaks on"/"leaks off" commands to MacsBug), EvenBetterBusError watches for dereferences of NIL and writes to NIL (location 0), and Xap fills pointers and handles that were disposed of with a value that causes a bus error if dereferenced. Furthermore, the useful system extension DoubleTrouble catches double disposes of a handle.

Another very useful tool from Apple is the Debugging Modern Memory Manager, which, not surprisingly, is a debugging version of the Modern Memory Manager. It performs many of the functions described in this article, including filling a client object's memory with garbage, checking for writes past the end of blocks, and checking for bad handles passed into Memory Manager routines.

Terminate

Well, there you have it. You've got TidyHeap hooked into your framework or application and you're ready to let it track your client objects and help you figure out where a leaky block was created, using either the TH_new macro or its block ID. You can now squash all your memory leaks with ease. You also learned about some of the more advanced features of TidyHeap, including the action classes that ship with it. And, you're ready to use TidyHeap Director to modify TidyHeap's behavior without recompiling your application.

I hope that TidyHeap makes it possible for you to focus on making insanely great software without having to worry so much about the more irritating and mundane tasks of application programming, such as tracking undeleted objects. Happy block hunting!

Thanks to our technical reviewers Brian Arnold, Paul Black, Geoff Clapp, Mike Rossetti, and Jason Yeo.

MACAPP NAMING CHANGES

The MacApp team is working to make MacApp a less monolithic framework. Whenever practical and possible, we're designing and implementing MacApp's new features so that they can be used independently of MacApp. TidyHeap is a prime example of this trend. Other features in development are networking support, cooperative and multiprocessing threading support, OpenDoc container support (ALOE, the Apple Library for Object Embedding), and such useful things as enhanced Standard Template Library (STL) support and a handful of C++ design patterns (useful abstractions for common problems). We're calling this collection of features "Apple Classes," but that may not be the final name.

We want everyone to be able to use Apple Classes without running into namespace and file inclusion collisions, so after much heated debate, we decided to adopt and adapt the OpenDoc Development Framework (ODF) naming convention until we get universal support for C++ namespaces in all our compilers. That's why all the TidyHeap classes are named AC_CClassName. The "AC" stands for "Apple Classes" and represents the scope of the class (ODF begins names with "FW" for "Framework"). The underscore conceptually represents the C++ scope operator (::). (For example, AC_CTidyHeap will become AppleClasses::CTidyHeap when C++ namespaces are supported.) The second "C" in "AC_C" represents the usage of the class - "C" for classes, "M" for mixin classes, and "S" for structs.

Filenames in Apple Classes significantly diverge from the ODF naming convention. ODF is cross-platform (Windows and Macintosh), so all its files conform to the Windows 8-character maximum. Because we don't need to do this, we decided to make the filename the same as the class name with a slight twist, which is that we append "_AC" to the class name like this: CTidyHeap_AC.h. We put the difficult-to-type underscore at the end to make life easier in dealing with the files in the Finder and for situations where you would want to use type-ahead, such as in a CodeWarrior project window.

If the TidyHeap classes accompanying this article begin with letters other than "AC," it's because a different name for the collection of features referred to here as Apple Classes was adopted after this article was published.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links... | Read more »
Price of Glory unleashes its 1.4 Alpha u...
As much as we all probably dislike Maths as a subject, we do have to hand it to geometry for giving us the good old Hexgrid, home of some of the best strategy games. One such example, Price of Glory, has dropped its 1.4 Alpha update, stocked full... | Read more »
The SLC 2025 kicks off this month to cro...
Ever since the Solo Leveling: Arise Championship 2025 was announced, I have been looking forward to it. The promotional clip they released a month or two back showed crowds going absolutely nuts for the previous competitions, so imagine the... | Read more »
Dive into some early Magicpunk fun as Cr...
Excellent news for fans of steampunk and magic; the Precursor Test for Magicpunk MMORPG Crystal of Atlan opens today. This rather fancy way of saying beta test will remain open until March 5th and is available for PC - boo - and Android devices -... | Read more »
Prepare to get your mind melted as Evang...
If you are a fan of sci-fi shooters and incredibly weird, mind-bending anime series, then you are in for a treat, as Goddess of Victory: Nikke is gearing up for its second collaboration with Evangelion. We were also treated to an upcoming... | Read more »
Square Enix gives with one hand and slap...
We have something of a mixed bag coming over from Square Enix HQ today. Two of their mobile games are revelling in life with new events keeping them alive, whilst another has been thrown onto the ever-growing discard pile Square is building. I... | Read more »
Let the world burn as you have some fest...
It is time to leave the world burning once again as you take a much-needed break from that whole “hero” lark and enjoy some celebrations in Genshin Impact. Version 5.4, Moonlight Amidst Dreams, will see you in Inazuma to attend the Mikawa Flower... | Read more »
Full Moon Over the Abyssal Sea lands on...
Aether Gazer has announced its latest major update, and it is one of the loveliest event names I have ever heard. Full Moon Over the Abyssal Sea is an amazing name, and it comes loaded with two side stories, a new S-grade Modifier, and some fancy... | Read more »
Open your own eatery for all the forest...
Very important question; when you read the title Zoo Restaurant, do you also immediately think of running a restaurant in which you cook Zoo animals as the course? I will just assume yes. Anyway, come June 23rd we will all be able to start up our... | Read more »
Crystal of Atlan opens registration for...
Nuverse was prominently featured in the last month for all the wrong reasons with the USA TikTok debacle, but now it is putting all that behind it and preparing for the Crystal of Atlan beta test. Taking place between February 18th and March 5th,... | Read more »

Price Scanner via MacPrices.net

AT&T is offering a 65% discount on the ne...
AT&T is offering the new iPhone 16e for up to 65% off their monthly finance fee with 36-months of service. No trade-in is required. Discount is applied via monthly bill credits over the 36 month... Read more
Use this code to get a free iPhone 13 at Visi...
For a limited time, use code SWEETDEAL to get a free 128GB iPhone 13 Visible, Verizon’s low-cost wireless cell service, Visible. Deal is valid when you purchase the Visible+ annual plan. Free... Read more
M4 Mac minis on sale for $50-$80 off MSRP at...
B&H Photo has M4 Mac minis in stock and on sale right now for $50 to $80 off Apple’s MSRP, each including free 1-2 day shipping to most US addresses: – M4 Mac mini (16GB/256GB): $549, $50 off... Read more
Buy an iPhone 16 at Boost Mobile and get one...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering one year of free Unlimited service with the purchase of any iPhone 16. Purchase the iPhone at standard MSRP, and then choose... Read more
Get an iPhone 15 for only $299 at Boost Mobil...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering the 128GB iPhone 15 for $299.99 including service with their Unlimited Premium plan (50GB of premium data, $60/month), or $20... Read more
Unreal Mobile is offering $100 off any new iP...
Unreal Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering a $100 discount on any new iPhone with service. This includes new iPhone 16 models as well as iPhone 15, 14, 13, and SE... Read more
Apple drops prices on clearance iPhone 14 mod...
With today’s introduction of the new iPhone 16e, Apple has discontinued the iPhone 14, 14 Pro, and SE. In response, Apple has dropped prices on unlocked, Certified Refurbished, iPhone 14 models to a... Read more
B&H has 16-inch M4 Max MacBook Pros on sa...
B&H Photo is offering a $360-$410 discount on new 16-inch MacBook Pros with M4 Max CPUs right now. B&H offers free 1-2 day shipping to most US addresses: – 16″ M4 Max MacBook Pro (36GB/1TB/... Read more
Amazon is offering a $100 discount on the M4...
Amazon has the M4 Pro Mac mini discounted $100 off MSRP right now. Shipping is free. Their price is the lowest currently available for this popular mini: – Mac mini M4 Pro (24GB/512GB): $1299, $100... Read more
B&H continues to offer $150-$220 discount...
B&H Photo has 14-inch M4 MacBook Pros on sale for $150-$220 off MSRP. B&H offers free 1-2 day shipping to most US addresses: – 14″ M4 MacBook Pro (16GB/512GB): $1449, $150 off MSRP – 14″ M4... Read more

Jobs Board

All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.