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

Whitethorn Games combines two completely...
If you have ever gone fishing then you know that it is a lesson in patience, sitting around waiting for a bite that may never come. Well, that's because you have been doing it wrong, since as Whitehorn Games now demonstrates in new release Skate... | Read more »
Call of Duty Warzone is a Waiting Simula...
It's always fun when a splashy multiplayer game comes to mobile because they are few and far between, so I was excited to see the notification about Call of Duty: Warzone Mobile (finally) launching last week and wanted to try it out. As someone who... | Read more »
Albion Online introduces some massive ne...
Sandbox Interactive has announced an upcoming update to its flagship MMORPG Albion Online, containing massive updates to its existing guild Vs guild systems. Someone clearly rewatched the Helms Deep battle in Lord of the Rings and spent the next... | Read more »
Chucklefish announces launch date of the...
Chucklefish, the indie London-based team we probably all know from developing Terraria or their stint publishing Stardew Valley, has revealed the mobile release date for roguelike deck-builder Wildfrost. Developed by Gaziter and Deadpan Games, the... | Read more »
Netmarble opens pre-registration for act...
It has been close to three years since Netmarble announced they would be adapting the smash series Solo Leveling into a video game, and at last, they have announced the opening of pre-orders for Solo Leveling: Arise. [Read more] | Read more »
PUBG Mobile celebrates sixth anniversary...
For the past six years, PUBG Mobile has been one of the most popular shooters you can play in the palm of your hand, and Krafton is celebrating this milestone and many years of ups by teaming up with hit music man JVKE to create a special song for... | Read more »
ASTRA: Knights of Veda refuse to pump th...
In perhaps the most recent example of being incredibly eager, ASTRA: Knights of Veda has dropped its second collaboration with South Korean boyband Seventeen, named so as it consists of exactly thirteen members and a video collaboration with Lee... | Read more »
Collect all your cats and caterpillars a...
If you are growing tired of trying to build a town with your phone by using it as a tiny, ineffectual shover then fear no longer, as Independent Arts Software has announced the upcoming release of Construction Simulator 4, from the critically... | Read more »
Backbone complete its lineup of 2nd Gene...
With all the ports of big AAA games that have been coming to mobile, it is becoming more convenient than ever to own a good controller, and to help with this Backbone has announced the completion of their 2nd generation product lineup with their... | Read more »
Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »

Price Scanner via MacPrices.net

Deal Alert! B&H Photo has Apple’s 14-inch...
B&H Photo has new Gray and Black 14″ M3, M3 Pro, and M3 Max MacBook Pros on sale for $200-$300 off MSRP, starting at only $1399. B&H offers free 1-2 day delivery to most US addresses: – 14″ 8... Read more
Department Of Justice Sets Sights On Apple In...
NEWS – The ball has finally dropped on the big Apple. The ball (metaphorically speaking) — an antitrust lawsuit filed in the U.S. on March 21 by the Department of Justice (DOJ) — came down following... Read more
New 13-inch M3 MacBook Air on sale for $999,...
Amazon has Apple’s new 13″ M3 MacBook Air on sale for $100 off MSRP for the first time, now just $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD/Space Gray): $999 $100 off MSRP... Read more
Amazon has Apple’s 9th-generation WiFi iPads...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Discounted 14-inch M3 MacBook Pros with 16GB...
Apple retailer Expercom has 14″ MacBook Pros with M3 CPUs and 16GB of standard memory discounted by up to $120 off Apple’s MSRP: – 14″ M3 MacBook Pro (16GB RAM/256GB SSD): $1691.06 $108 off MSRP – 14... Read more
Clearance 15-inch M2 MacBook Airs on sale for...
B&H Photo has Apple’s 15″ MacBook Airs with M2 CPUs (8GB RAM/256GB SSD) in stock today and on clearance sale for $999 in all four colors. Free 1-2 delivery is available to most US addresses.... Read more
Clearance 13-inch M1 MacBook Airs drop to onl...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray, Silver, & Gold) in stock and on clearance sale today for $300 off MSRP, only $699. Free 1-2 day shipping is available to most addresses in... Read more
New promo at Visible: Buy a new iPhone, get $...
Switch to Visible, and buy a new iPhone, and Visible will take $10 off their monthly Visible+ service for 24 months. Visible+ is normally $45 per month. With this promotion, the cost of Visible+ is... Read more
B&H has Apple’s 13-inch M2 MacBook Airs o...
B&H Photo has 13″ MacBook Airs with M2 CPUs and 256GB of storage in stock and on sale for $100 off Apple’s new MSRP, only $899. Free 1-2 day delivery is available to most US addresses. Their... Read more
Take advantage of Apple’s steep discounts on...
Apple has a full line of 16″ M3 Pro and M3 Max MacBook Pros available, Certified Refurbished, starting at $2119 and ranging up to $600 off MSRP. Each model features a new outer case, shipping is free... Read more

Jobs Board

Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Business Analyst | *Apple* Pay - Banco Popu...
Business Analyst | Apple PayApply now " Apply now + Apply Now + Start applying with LinkedIn Start + Please wait Date:Mar 19, 2024 Location: San Juan-Cupey, PR Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.