[Insight-developers] how to attack memory leaks

Kent Williams norman-k-williams at uiowa.edu
Wed Jun 15 11:34:29 EDT 2005


We use valgrind, which is Linux- and Intel- specific.  It doesn't 
require anything specific of the compiled program, except that it be 
compiled and linked with debugging on. It's free software and can be 
obtained at  http://valgrind.org/

I recently used valgrind to find a similar problem, and can offer this 
advice if you try it:

1. Execution time can be ten times normal execution since valgrind does 
a instruction-by-instruction intepretation.  If there's any way to cut 
down the size of your problem, you should do so.

2. valgrind keeps exhaustive information about memory leaks/errors, so 
it consumes memory greedily. If your program currently runs until it 
uses up available memory and then dies, valgrind will run out of memory 
as well, and quit without generating a report.  Consequently, you will 
have to modify your program to exit after some memory has been leaked, 
but before all memory is exhausted.

3. Valgrind often reports the same execution error or memory leak many, 
many times, depending on the execution path of your program. I wrote a 
quick-and-dirty program (attached) that cleans up the valgrind output 
and removes most duplicate reports.  Valgrind also has ways to suppress 
error messages for files/libraries you don't care to debug, but building 
a good exclusion file is pretty tedious, since you have to run your 
program under valgrind with a special flag to generate the exclusion 
clauses.

4. As good as valgrind is, it can be fooled, and regularly reports leaks 
where I suspect none is occuring. Something as basic as an assignement 
to a std::string can generate a leak report.

All that being said, valgrind takes a lot of the sweat out of debugging 
memory problems, and can be a tremendous time saver. You might need to 
run it overnight to get useful results, but it's free software, and gets 
good results.

Leila baghdadi wrote:

>hi everyone,
>
>I have that uses a number of itk classes to perform some segmentation, I
>know that at least one of the classes has a leak, I can see how its
>memory usage grows as the program proceeds until at some point it dies,
>
>Unfortunately, I do not have any good program to solve this problem, I
>tried disconnecting the pipeline and deleting the previous filters but
>no luck,
>
>I am basically looking for some suggestions to fix this problem,
>
>Thanks for your time
>
>Leila
>
>_______________________________________________
>Insight-developers mailing list
>Insight-developers at itk.org
>http://www.itk.org/mailman/listinfo/insight-developers
>
>  
>
-------------- next part --------------
// valgrindmassage.cxx
// a program to reduce valgrind output to manageable proportions.
// usage: valgrindmassage <valgrind-output-file>
// writes massaged report on standard output.
//
// norman-k-williams at uiowa.edu
#include <iostream>
#include <string>
#include <fstream>
#include <list>
#include <ctype.h>
void
fix_error(std::string &s)
{
  std::string::size_type loc;
  bool possible;
  if((possible = s.find("are possibly lost") != std::string::npos) ||
     s.find("are definitely lost") != std::string::npos)
    {
    std::string::size_type first_newline =
      s.find('\n');
    if(first_newline != std::string::npos)
      {
      std::string s2 = (possible ? "Possible " : "Definite ");
      s2 += "Memory Leak\n";
      s2 += s.substr(first_newline+1);
      s = s2;
      }
    }
  std::string::size_type cur;
  loc = 0;
  while(loc != std::string::npos &&
        (loc = s.find("0x",loc)) != std::string::npos)
    {
    cur = loc + 2;
    while(cur != std::string::npos &&
          isxdigit(s[cur]))
      {
      cur++;
      }
    s.erase(loc,cur-loc);
    }
}

bool exclude(const std::string &s)
{
  static const char *exclusions[] = 
    {
    "LEAK SUMMARY",
    "ERROR SUMMARY",
    "GNU GPL",
    "getpwuid",
    "tclInstallCommands",
    "TclCreateExecEnv",
    "itk::MultiThreader",
    0
    };
  unsigned i;
  for(i = 0; exclusions[i] != 0 ; i++)
    {
    if(s.find(exclusions[i]) != std::string::npos)
      {
      return true;
      }
    }
  return false;
}
bool exclude_useless_leak_reports(const std::string &s)
{
  std::string::size_type stackentry = 0;
  if(s.find("by : ") != std::string::npos)
    {
    while(s.find("by : ",stackentry) != std::string::npos)
      {
      stackentry += 5;
      std::string::size_type address = s.find("???",stackentry,3);
      if(address == std::string::npos)
        {
        return false;
        }
      }
    return true;
    }
  return false;
}
int
main(int argc,char **argv)
{
  if(argc != 2)
    {
    std::cerr << "Oops" << std::endl;
    exit(-1);
    }
  std::ifstream in(argv[1]);
  std::list<std::string> message_blocks;
  std::string s;
  std::string accumulator;
  int total_count, net_count;
  while(getline(in,s))
    {
    if(s.find("==") != 0)
      {
      continue;
      }
    if(s[s.size()-1] == ' ') // a line with nothing on it terminates an entry
      {
      if(accumulator != "")
        {
        if(exclude(accumulator))
          {
          accumulator = "";
          }
        else
          {
          fix_error(accumulator);
          if(!exclude_useless_leak_reports(accumulator))
            {
            message_blocks.push_back(accumulator);
            }
          accumulator = "";
          }
        }
      }
    else
      {
      accumulator += s.substr(9);
      accumulator += '\n';
      }
    }

  total_count = message_blocks.size();
  message_blocks.sort();
  message_blocks.unique();
  net_count = message_blocks.size();
  std::list<std::string>::iterator it;
  for(it = message_blocks.begin();
      it != message_blocks.end();
      it++)
    {
    std::cout << (*it);
    std::cout << "---------------------------" << std::endl;
    }
  std::cout << "Total Count " << total_count << " Net Count " <<
    net_count << std::endl;
}


More information about the Insight-developers mailing list