Site Tools


Info: Finding and Fixing Memory Leaks

C++

Versions: Rhino 4 and Rhino 5

The Rhino 4.0 and Rhino 5.0 SDKs ship 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 Output window.

   Detected memory leaks!
   Dumping objects ->
   {172871} normal block at 0x0..., 1260 bytes long.
    Data: <ONmemory...> ...
   {172870} normal block at 0x0..., 1259 bytes long.
    Data: <ONmemory...> ...
   {172869} normal block at 0x0..., 1258 bytes long.
    Data: <ONmemory...> ...

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 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, three leaks are listed. 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 leaked. The allocation serial number and address depend on everything that happened up to the time the memory was leaked. They generally change 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: <ONmemory...> ...

the memory was allocated with Rhino's onmalloc, onrealloc, or Rhino's new. (ONmemory stands for openNURBS memory 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 “ONmemory” 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 more 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 more information about this leak.

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 ONmemory leaks of 1258, 1259, and 1260 bytes. To get more information about these leaks run the LookForLeaks command and specify 1258 as the minimum size and 1260 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 1295, 1299, and 1303 of a file called cmdleakdetector.cpp.

   RHINO LEAK DETECTION: Listing memory leaks ...
   LEAK {172869} 0x0BE5BE20, 1258 bytes.
      onmalloc opennurbs_memory.c Line 284
      CCommandTestLeakDetection::RunCommand cmdleakdetector.cpp Line 1295
      CRhinoApp::ExecuteCommand rhino3runcommand.cpp Line 1884
      ...
   LEAK {172870} 0x0BE5C370, 1259 bytes.
      onmalloc opennurbs_memory.c Line 284
      operator new[] opennurbs_memory_new.cpp Line 84
      CCommandTestLeakDetection::RunCommand cmdleakdetector.cpp Line 1299
      CRhinoApp::ExecuteCommand rhino3runcommand.cpp Line 1884
      ...
   LEAK {172871} 0x0BE5C8C0, 1260 bytes.
      onrealloc opennurbs_memory.c Line 335
      CCommandTestLeakDetection::RunCommand cmdleakdetector.cpp Line 1303
      CRhinoApp::ExecuteCommand rhino3runcommand.cpp Line 1884
      ...
   Leak dump complete.
      ...
   Detected memory leaks!1:20 PM 8/2/2012
   Dumping objects ->
   {172871} normal block at 0x000000000BE5C8C0, 1260 bytes long.
    Data: <ONmemory...> ...
   {172870} normal block at 0x000000000BE5C370, 1259 bytes long.
    Data: <ONmemory...> ...
   {172869} normal block at 0x000000000BE5BE20, 1258 bytes long.
    Data: <ONmemory...> ...
   {121901} normal block at 0x0..., ... 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. The allocation number (the number in wiggly brackets) on the left side of the “NOT A LEAK” line indicates when LookForLeaks started. Any leaks with allocation numbers smaller than this number happened before LookForLeaks started. In the example above, 121901 is the allocation number when LookForLeaks started. If you need to track down a leak that is happening before the first command can 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.

developer/debugmemoryleaks.txt · Last modified: 2017/02/14 by dalelear