Rhino4 Debug Memory Leaks
Last changed: -204.177.179.86

.
DeveloperC++
VersionRhino 4

The Rhino 4.0 SDK ships with support for building fully debuggable plug-ins that use the debug MFC and CRT.

Discovering Memory Leaks Exist

When you use the debugger to run a debug configuration of a plug-in built with the Rhino SDK, after you exit Rhino the Microsoft debug CRT checks for memory leaks and reports them in the Visual Studio 8 Output window.

You should get in the habit of checking the Output window when working on your plug-in. If you see a "Detected memory leaks!" section near the end of the Output window, then your program is leaking memory. Memory leaks are serious bugs that need to be fixed. The Rhino 4 Debug SDK provides a built in tool for finding the location where the leaked memory was allocated.

Determining Which Allocator Leaked the Memory

In the image above, 6 leaks are listed.

  Detected memory leaks!
  Dumping objects ->
  {70451} normal block at 0x0C30F890, 59 bytes long.
   Data: <        ONmemory> ...
  {70450} client block at 0x0C2C2360, subtype c0, 8 bytes long.
  a CBitmap object at $0C2C2360, 8 bytes long
  {70449} normal block at 0x0C328230, 542 bytes long.
   Data: <        ONmemory> ...
  {70448} normal block at 0x0C30F370, 1252 bytes long.
   Data: <        ONmemory> ...
  {70447} normal block at 0x0C30EE50, 1251 bytes long.
   Data: <        ONmemory> ...
  {70446} normal block at 0x0C327D10, 1250 bytes long.
   Data: <        ONmemory> ...
  Object dump complete.

There are two lines for each leak. The first line

  {.....} ... block at 0x..., ... bytes long.

reports the debug CRT allocation serial number (the number in wiggly brackets), the address of the first byte of leaked memory, and the number of bytes that were leaked. The allocation serial number and address depend on everything that has happened up to the time the memory was leaked and generally change a bit each time you run your plug-in.

The second line generally looks like

   Data: <...> ...

or

   a CSomeMFCObject object at $..., ... bytes long

If the second line looks like

   Data: <    ONal....ONal> ...

the memory was allocated with Rhino's onmalloc, onrealloc, or Rhino's new. ("ONal" stands for OpenNURBS allocation.) The Rhino Debug SDK can tell you the complete callstack at the time the memory was allocated.

If the second line starts with "Data:" but doesn't have an "ONal" between the angle brackets, then the memory was allocated by directly calling the CRT malloc(), calloc(), realloc(), new or another function. The Rhino Debug SDK cannot give you any additional information about this leak.

If the second line starts with "a CSomeMFCObject object ...", then the memory was allocated by calling new CSomeMFCObject. The Rhino Debug SDK cannot give you any additional information about this leak.

If you see "Data: <ON_MEMORY_POOL >" lines, these are memory pools used by the Rhino cancel mechanism. You may safely ignore these.

Using LookForLeaks to Get Allocation Callstacks

The Debug Rhino (rhino_d.exe) that is shipped with the Rhino Debug SDK has a command called LookForLeaks. The LookForLeaks command turns on code that will print the callstack when the leaked memory was allocated. The LookForLeaks command asks you to specify the minimum and maximum size of allocations to list. In the example above there are "ONal" leaks of 59, 1250, 1251 and 1252 bytes. To get more information about these leaks you would run the LookForLeaks command and specify 59 as the minimum size and 1252 as the maximum size. When LookForLeaks is running, Rhino runs much slower than it ordinarily does. Setting the minimum and maximum size close together can significantly speed up program execution.

Below is what you see in the Output window if the LookForLeaks command is run right after Rhino starts. The "LEAK {...}..." sections report the callstack at the time of the allocation. From this information we can see that the function CCommandTestLeakDetection::RunCommand is leaking memory that is allocated on lines 1275, 1279, 1283, and 1219 of a file called cmdleakdetector.cpp.

  RHINO LEAK DETECTION: Listing memory leaks ...
  LEAK {63520} 0x0C32C6C8, 59 bytes.
     onmalloc opennurbs_memory.c Line 220
     CCommandTestLeakDetection::RunCommand cmdleakdetector.cpp Line 1291
     ...
  LEAK {63517} 0x0C32BF48, 1252 bytes.
     onrealloc opennurbs_memory.c Line 261
     CCommandTestLeakDetection::RunCommand cmdleakdetector.cpp Line 1283
     ...
  LEAK {63516} 0x0C32BA28, 1251 bytes.
     onmalloc opennurbs_memory.c Line 220
     operator new[] opennurbs_memory_new.cpp Line 56
     CCommandTestLeakDetection::RunCommand cmdleakdetector.cpp Line 1279
     ...
  LEAK {63515} 0x0C32B508, 1250 bytes.
     onmalloc opennurbs_memory.c Line 220
     CCommandTestLeakDetection::RunCommand cmdleakdetector.cpp Line 1275
     ...
  ...
  Leak dump complete.
  The thread 'Win32 Thread' (0xa18) has exited with code 0 (0x0).
  The thread 'Win32 Thread' (0x108) has exited with code 0 (0x0).
  The thread 'Win32 Thread' (0xe58) has exited with code 0 (0x0).
  Detected memory leaks!
  Dumping objects ->
  {63520} normal block at 0x0C32C6C8, 59 bytes long.
   Data: <    ONal 'r ONal> ...
  {63519} client block at 0x0C26FFE0, subtype c0, 8 bytes long.
  a CBitmap object at $0C26FFE0, 8 bytes long
  {63518} normal block at 0x0C32C468, 542 bytes long.
   Data: <                > ...
  {63517} normal block at 0x0C32BF48, 1252 bytes long.
   Data: <    ONalh&r ONal> ...
  {63516} normal block at 0x0C32BA28, 1251 bytes long.
   Data: <    ONalH%r ONal> ...
  {63515} normal block at 0x0C32B508, 1250 bytes long.
   Data: <    ONal($r ONal> ...
  {46422} normal block at 0x0C232520, 56 bytes long.
   Data: <NOT A LEAK      > ...
  Object dump complete.

The "Data: <NOT A LEAK >" leak listed on the last line is memory used by the Rhino leak detector. In the CRT dump, the gibberish between the "ONal" markers is actually a pointer to the LEAK callstack information. If you see a

  Data: <    ONal    ONal> ...

line, it means the allocation happened before LookForLeaks was started. If you need to track down a leak that is happening before the first command can be run, you can use the /lookforleaks=min,max command line switch.

If you are debugging leaks in code that is in your plug-in, be sure to load your plug-in before running the LookForLeaks command. You can use the "PlugInManager" command to load your plug-in.