`
haoningabc
  • 浏览: 1485004 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

c++内存泄露

    博客分类:
  • c
 
阅读更多

转http://www.codeproject.com/Articles/393957/Cplusplus-Memory-Leak-Finder

Introduction  

  In this article I will discuss a way to build a memory leak detection program for C and C++ applications.
This is not an attempt at writing a fully fledged leak detector but rather an introduction to one way (of many) ways of finding leaks.

  The approach I've gone for is library injection and even if the C++ source code provided is for Linux (tested on Ubuntu 11.10) the method should work for any platform that allows library injection.


What is a leak

  There are many ways in which an application can leak resources, and there are many different resources that can be leaked.   In this article I'll focus on and only look for memory leaks (not file handles or sockets or any other resource that might be allocated), but even when constraining the scope to just memory there are still many different kinds of leaks.   When talking about memory leaks in C++, most people think of scenarios like this (very simplified one);

 Collapse | Copy Code
void foo()
{
  int* my_pointer = new int;
}   // my_pointer is never deleted, we've just leaked sizeof(int) bytes!
  Memory is allocated but is not deleted/unallocated before the reference to the allocated memory goes out of scope. This means of course that   the memory will be unavailable for use as well as for further allocations until the program terminates.

  But memory leaks can appear in other more subtle ways as well, sometimes the memory is still referenced but just not used, such as when items are regularly added to a std::vector without ever being released. If such a std::vector is never cleared and still never again looked at by the application it can be considered leak, even though the memory is still referenced.

  In this article, for simplicity, I'll only look at the first scenario; allocated memory that is not deallocated. In short, I'll show a way of tracking each call to malloc and free and record information so that they can be married up.

  You might argue that you're using C++ and are therefore allocating and deallocating your memory using new and delete but in most cases the implementation of those will still call the C versions malloc and free.

Library Injection

  Library Injection is when a user tells the OS to first look in LibraryA for system wide methods before looking in the "standard" libraries, where LibraryA is a library containing an overload of a system function. On some Linux and Unix distributions this can be achieved using the LD_PRELOAD environment variable to set the library that is to be injected.   

  To track memory allocations and deallocations a shared library containing overloads for malloc and free must be created and then injected so that whenever an allocation of memory is requested the custom version is hit first.   

  First step is to create a C++ file, leakfinder.cpp, that will contain the two methods;

 Collapse | Copy Code
#include<iostream>

void* malloc(size_t size)
{
  std::cout << "malloc called" << std::endl;
  // Somehow track this allocation
}

void free(void* ptr)
{
  std::cout << "free called" << std::endl;
  // Somehow marry up this deallocation to a previous allocation
}
  The above example can be compiled into a shared library using g++ (which is the compiler I'll use for the C++ code through out this article) by running:

 Collapse | Copy Code
  ~/SomeFolder$g++ -shared -fPIC leakfinder.cpp -o leakfinder.so -ldl
  Using an example C program that is built to leak we can test this, the example C program is called c_example and it looks like this:

 Collapse | Copy Code
#include <stdlib.h>
#include <stdio.h>

void foo(int size)
{
  int* data = malloc(sizeof(int) * size);
  // Uncomment this to stop leak
  //free(data);
}

void bar(int size)
{
  char *data = malloc(sizeof(char) * size);
  foo(size);
  // Uncomment this to stop leak
  //free(data);
}

void foobar(int size)
{
  bar(size);  
}

int main(void)
{
  printf("leakfinder C example app\n");
  printf("This application is expected to leak\n");

  foobar(8);
  foobar(16);

  printf("leakfinder C example app all done\n");
  return 0;
}
  Important!   
      It is important to test the injection in a terminal other than the one used to compile the source code or the injection might (will) interfere with the compiler and any other commands that use malloc or free.
    Therefore, when working with this example make sure you have one terminal open for compiling and building (both the leak finder and the example applictions), and one where the LD_PRELOAD environment variable is set where you can run the test applications.  


Another way of making sure the pre-load only is applicable for the c_example application is by running it like this; LD_PRELOAD=./leakfinder.so c_example. 

  Set the LD_PRELOAD in your terminal to point to the leakfinder.so and run the c_example test application using;  

 Collapse | Copy Code
    ~/SomeFolder$export LD_PRELOAD=./leakfinder.so 
 
 Collapse | Copy Code
    ~/SomeFolder$./c_example 
  When first run it turns out that no allocations or deallocations are detected, this is because of the linkage. As g++ (a C++ and not a C compiled) was used to compile the leakfinder.cpp file it has applied name mangling and that means he function names do not match the intended system functions malloc and free. To resolve this issue the functions has to be declared with C linkage:

 Collapse | Copy Code
#include<iostream>

extern "C" void* malloc(size_t size)
{
  std::cout << "malloc called" << std::endl;
  // Somehow track this allocation
}

extern "C" void free(void* ptr)
{
  std::cout << "free called" << std::endl;
  // Somehow marry up this deallocation to a previous allocation
}
  When the leak finder with the correct linkage is preloaded and the example is run it will generate an output that looks something like this;


  Loads and loads of allocations and deallocations intercepted!
  This is because even though the test application only explicitly allocates a few things other parts also allocates and deallocates stuff, such as the printf and even the cout calls in the injected code.

  The print out ends with a Segmentation fault which is of course because you cannot hope to replace an actual memory allocation with a print statement and expect stuff to still work  " /> , but the method is proved to work.

Actual implementation

  As it is clearly very important for the overloaded methods malloc and free to still do the work they are intended to do (as in allocating and deallocating memory on and from the heap) the injected code must look up pointers to the actual implementation and delegate the calls to these before tracking them.

Finding it

  To find the actual implementation is done by calling dlsym (defined in dlfcn.h), this function returns function pointers to functions made available using dlopen. Using the constant RTLD_NEXT the previous entry can be retrieved, and that pointer can be stored in a static variable to cache it so the lookup doesn't have to take place every time;

 Collapse | Copy Code
static void* (*sys_malloc)(size_t) = 0;
static void (*sys_free)(void*) = 0;

static void initialize_functions(void)
{
  sys_malloc = reinterpret_cast<void*(*)(size_t)>(dlsym(RTLD_NEXT, "malloc"));
  if (sys_malloc == 0)
    cerr << "leakfinder failed to read malloc function; " << dlerror() << endl;

  sys_free = reinterpret_cast<void(*)(void*)>(dlsym(RTLD_NEXT, "free"));
  if (sys_free == 0)
    cerr << "leakfinder failed to read free function; " << dlerror() << endl;
}

extern "C" void* malloc(size_t size)
{
  cout << "malloc called" << endl;
  if (sys_malloc == 0)
    initialize_functions();

  void* ptr = sys_malloc(size);

  return ptr;
}

 Collapse | Copy Code
extern "C" void free(void* ptr)
{
  cout << "free called" << endl;

  if (sys_free == 0)
    initialize_functions();

  sys_free(ptr);
}
  In the code above the system version (or standard version) of malloc and free are looked up using dlsym(RTLD_NEXT, [name of function]) and then stored in sys_malloc and sys_free respectively.   
  After the system version of the functions are cached (if not already cached) they're called to perform the allocation or deallocation and after that the leak finder will intercept the calls to track the information required to compile a list of leaks.

Allocation Info

  To allow the user to fix leaks, each leak needs to be associated with additional information to make it easy to track down the leak and correct it, in leakfinder I track four different things;  

   
References
   
Stacktrace
   
Size
   
Thread
 
References

  In order to marry up a deallocation to a previous allocation there need to be something that is unique and consistent across malloc and free calls, and one thing that can be used is the address of the allocated memory. It has to be unique as no two allocations are allowed to get the same piece of memory and it's consistent across calls as it's the return value of the allocation and the parameter to the deallocation.

Stacktrace

  In order for a memory leak detector to be useful it needs to be able to tell the user where the leak was allocated.   One way to get a stacktrace in Linux is to use the backtrace and backtrace_symbols functions in execinfo.h.

  Function backtrace gets all the return addresses for all the functions that are currently active on the stack in a particular thread, which is essentially the stacktrace.   
  In order to get a more readable version of the stacktrace the return addresses from backtrace can be fed into backtrace_symbols to get the names of the functions on the stack.

 Collapse | Copy Code
  void* frames[max_frame_depth];
  size_t stack_size = backtrace(frames, max_frame_depth);
  char** stacktrace = backtrace_symbols(frames, stack_size);
Size and Thread

  Less important but still sometimes useful is to record the size of the allocation and which thread it was allocated on.

  The size is passed in as a size_t argument to malloc so that is easy enough to grab and record.

  Recording the current thread id might be slightly harder depending on the thread library used, in this example I've used the pthread library so I get the thread id as a pthread_t by calling pthread_self().

allocation_info

  The information listed above, reference, stacktrace, size and thread are in leakfinder stored in a class called allocation_info.

allocation_info.hpp

 Collapse | Copy Code
#ifndef __allocation_info
#define __allocation_info

#include <vector>
#include <string>

#include <pthread.h>

namespace bornander
{
  namespace memory
  {
    class allocation_info
    {
    public:
      typedef long long address_type;

    private:
      allocation_info::address_type address;
      size_t size;
      std::vector<std::string> stacktrace;
      pthread_t thread_id;

    public:
      allocation_info(void* address, size_t size, char** stacktrace, size_t depth, pthread_t thread_id);

      allocation_info::address_type get_address() const;
      size_t get_size() const;
      std::vector<std::string> get_stacktrace() const;
      pthread_t get_thread_id() const;
    };
  }
}

#endif
allocation_info.cpp

 Collapse | Copy Code
#include "allocation_info.hpp"

namespace bornander
{
  namespace memory
  {
    allocation_info::allocation_info(void* address, size_t size, char** stacktrace, size_t depth, pthread_t thread_id)
    {
      this->address = reinterpret_cast<allocation_info::address_type>(address);
      this->size = size;
      this->thread_id = thread_id;

      // Skip first frame as that is the overriden malloc method
      for(int i = 1; i < depth; ++i)
      {
        std::string frame = stacktrace[i];
        this->stacktrace.push_back(frame);
      }
    }

    allocation_info::address_type allocation_info::get_address() const
    {
      return address;
    }

    size_t allocation_info::get_size() const
    {
      return size;
    }

    std::vector<std::string> allocation_info::get_stacktrace() const
    {
      return stacktrace;
    }

    pthread_t allocation_info::get_thread_id() const
    {
      return thread_id;
    }
  }
}
Tracking leaks

  Armed with a way of intercepting allocations (library injection) and a way to store allocation information (allocation_info) we're now ready to implement our basic memory leak detector.

Allocations

  The first problem with tracking allocations inside the allocation method is that to track it memory needs to be allocated to store the allocation_info, and that obviously means that for every allocation another allocation is required. Since the additional allocation uses malloc as well the approach leads to a stack overflow.

  The solution is to only track allocations that are originating from outside of leakfinder. By declaring a static boolean called isExternalSource that is set to false before the allocation is recorded and back to true when done it is possible to exclude allocation that arise from recording the source allocation. The overloaded malloc method then looks something like this;

 Collapse | Copy Code
static bool isExternalSource = true;
static void* (*sys_malloc)(size_t) = 0;

extern "C" void* malloc(size_t size)
{
  // Make sure we're initialized
  if (sys_malloc == 0)
    initialize_functions();
 Collapse | Copy Code
  // Call the actual malloc and keep the result
 Collapse | Copy Code
  void* ptr = sys_malloc(size);

  if (isExternalSource)
  {
    isExternalSource = false;
    // Record the details of this allocation in an allocation_info
    isExternalSource = true;
  }

  return ptr;
}
  This takes care of the exclusion of internal allocation but suffers from threading issues as the static isExternalSource might be read/written by two threads at the same time causing undefined behaviour.

  By guarding the inside of the if-statement with a lock (using pthread threads) the malloc method changes to this;

 Collapse | Copy Code
static pthread_mutex_t cs_mutex = PTHREAD_MUTEX_INITIALIZER;

static bool isExternalSource = true;
static void* (*sys_malloc)(size_t) = 0;

extern "C" void* malloc(size_t size)
{
  // Make sure we're initialized
  if (sys_malloc == 0)
    initialize_functions();

  // Call the actual malloc and keep the result
  void* ptr = sys_malloc(size);

  if (isExternalSource)
  {
    pthread_t thread_id = pthread_self();
    pthread_mutex_lock(&cs_mutex);
    isExternalSource = false;

    // Record the allocation here
    isExternalSource = true;
    pthread_mutex_unlock(&cs_mutex);
  }

  return ptr;
}
  Now the malloc implementation is thread safe (or thread-safeish, it still suffers from some issues but for sake of simplicity I'm going to keep it this way for this article).   
  The rest of the implementation is the matter of grabbing the stacktrace and storing it along with the reference, size and thread id. The size is already passed in and the thread id has been grabbed using pthread_self, the remaining this to store is simply the reference which is the address of ptr which is returned by the actual implementation of malloc.

  All of the above yields a malloc function that looks like this;

 Collapse | Copy Code
static pthread_mutex_t cs_mutex = PTHREAD_MUTEX_INITIALIZER;

static size_t allocation_count = 0;
static vector<allocation_info> allocations;

static const size_t max_frame_depth = 128;
static bool isExternalSource = true;
static void* (*sys_malloc)(size_t) = 0;

extern "C" void* malloc(size_t size)
{
  if (sys_malloc == 0)
    initialize_functions();

  void* ptr = sys_malloc(size);

  if (isExternalSource)
  {
    pthread_t thread_id = pthread_self();
    pthread_mutex_lock(&cs_mutex);
    isExternalSource = false;

    // Used for summary statistics
    ++allocation_count;

    // Grab stacktrace
    void* frames[max_frame_depth];
    size_t stack_size = backtrace(frames, max_frame_depth);
    char** stacktrace = backtrace_symbols(frames, stack_size);
    allocation_info allocation(ptr, size, stacktrace, stack_size, thread_id);

    allocations.push_back(allocation);

    // Make sure to release the memory allocated by backtrace_symbols
    sys_free(stacktrace);  
 Collapse | Copy Code
    isExternalSource = true;

    pthread_mutex_unlock(&cs_mutex);
  }

  return ptr;
}
Deallocations

  To marry up a deallocation to a previous allocation is simple. The free uses the same method of preventing it to be run for an internal free and thread safety and in addition to this it's just a matter of finding the allocation_info in the allocations vector. The unique key is the reference or address;

 Collapse | Copy Code
extern "C" void free(void* ptr)
{
  if (sys_free == 0)
    initialize_functions();

  allocation_info::address_type address = reinterpret_cast<allocation_info::address_type>(ptr);
  sys_free(ptr);

  if (isExternalSource)
  {
    pthread_mutex_lock(&cs_mutex);
    isExternalSource = false;
    for (int i = 0; i < allocations.size(); ++i)
    {
      allocation_info allocation = allocations[i];
      if (allocation.get_address() == address)
      {
        allocations.erase(allocations.begin() + i);
        break;
      }
    }
    isExternalSource = true;
    pthread_mutex_unlock(&cs_mutex);
  }
}
Summing it up

  After all the allocations and deallocations have been tracked and matched off the ones that were never deallocated must be reported on, so when is a suitable time to do that?   
  Since it's pretty much technically impossible to tell if a leak has happened before the program terminates leakfinder uses program exit to sum up the leaks. One might argue that the leak happens when the pointer referencing the memory goes out of scope of the pointer has not been deallocated but since it is possible to store the pointer value in just about any other data structure that can be hard to rely on.

C style destructor

  There are different ways to hook into the termination of a program, which one to pick depends on platform and personal taste.   
  One approach is to use a pragma directive;

 Collapse | Copy Code
  #pragma fini (some_exit_handler)
  but for leakfinder I've gone for a C style destructor;

 Collapse | Copy Code
  static void compile_allocation() __attribute__((destructor));
  Using this approach, the method compile_allocation is executed when the shared library is unloaded, this is typically at program exit.

  Since all the not unallocated allocations are held in the vector allocations at program exit, the work of the compile_allocation method is just to iterate through the leaks and somehow output the leak information.   
  Where the best place to output the leak information to I am not entirely sure of. In certain scenarios a file would be convinient but for simplicity I've decided to let leakfinder just dump the summary to standard out.

  To avoid extra work isExternalSource needs to be set to false at the beginning of compile_allocaion as printing the summary requires allocations to take place.

  To print addresses and pointers in hex variables hex and dec from iomanip are used.

 Collapse | Copy Code
void compile_allocation()
{
  isExternalSource = false;
  if (allocations.empty())
  {
    cout << "leakfinder found no leaks, not one of the " << allocation_count;
    cout << " allocations was not released." << endl;
  }
  else
  {
    cout << "leakfinder detected that " << allocations.size();
    cout << " out of " << allocation_count << " allocations was not released." << endl;
    for (int i = 0; i < allocations.size(); ++i)
    {
      allocation_info allocation = allocations[i];
      cout << "Leak " << (i+1) << "@0x" << hex << allocation.get_thread_id() << dec;
      cout << "; leaked " << allocation.get_size() << " bytes at position 0x";
      cout << hex << allocation.get_address() << dec << endl;

      vector<string> stacktrace = allocation.get_stacktrace();
      for (int j = 0; j < stacktrace.size(); ++j)
      {
        cout << "\t" << stacktrace[j] << endl;
      }
    }
  }
}
Trying it out

  To try it out first build the leakfinder shared library by typing (there's also a makefile included for those who cares not for compiling by hand);

 Collapse | Copy Code
  g++ -shared -fPIC allocation_info.cpp leakfinder.cpp -o leakfinder.so -lpthread -ldl
  Then build the c_example shared library by typing;

 Collapse | Copy Code
  cc c_example.c -o c_example
  Then, open up a different terminal and set the LD_PRELOAD;

 Collapse | Copy Code
  export LD_PRELOAD=./leakfinder.so
  Lastly, run the c_example in the terminal where LD_PRELOAD was set;

 Collapse | Copy Code
  ./c_example
  Running that application should produce an output similar to this;


 Collapse | Copy Code
  fredrik@ubuntu-01:~/Development/leakfinder$ ./c_example
  leakfinder C example app
  This application is expected to leak
  leakfinder C example app all done
  leakfinder detected that 4 out of 4 allocations was not released.
  Leak 1@0xb77876d0; leaked 8 bytes at position 0x8e63020
    ./c_example() [0x804843e]
    ./c_example() [0x804845f]
    ./c_example() [0x804848e]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0xaef113]
    ./c_example() [0x8048381]
  Leak 2@0xb77876d0; leaked 32 bytes at position 0x8e632d0
    ./c_example() [0x8048428]
    ./c_example() [0x804844c]
    ./c_example() [0x804845f]
    ./c_example() [0x804848e]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0xaef113]
    ./c_example() [0x8048381]
  Leak 3@0xb77876d0; leaked 16 bytes at position 0x8e63230
    ./c_example() [0x804843e]
    ./c_example() [0x804845f]
    ./c_example() [0x804849a]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0xaef113]
    ./c_example() [0x8048381]
  Leak 4@0xb77876d0; leaked 64 bytes at position 0x8e63318
    ./c_example() [0x8048428]
    ./c_example() [0x804844c]
    ./c_example() [0x804845f]
    ./c_example() [0x804849a]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0xaef113]
    ./c_example() [0x8048381]
  fredrik@ubuntu-01:~/Development/leakfinder$
  While that has indeed first printed the output of c_example followed by the summary of the four leaks, the stactrace isn't very easy to dechiper. That is because the program is lacking symbols but by compiling it again (in the first terminal) with option -rdynamic this can be corrected;

 Collapse | Copy Code
  cc -rdynamic c_example.c -o c_example
  A more useful stacktrace is provided;

 Collapse | Copy Code
  fredrik@ubuntu-01:~/Development/leakfinder$ ./c_example
  leakfinder C example app
  This application is expected to leak
  leakfinder C example app all done
  leakfinder detected that 4 out of 4 allocations was not released.
  Leak 1@0xb76fb6d0; leaked 8 bytes at position 0x91d9020
    ./c_example(bar+0x11) [0x804860e]
    ./c_example(foobar+0x11) [0x804862f]
    ./c_example(main+0x2d) [0x804865e]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x144113]
    ./c_example() [0x8048551]
  Leak 2@0xb76fb6d0; leaked 32 bytes at position 0x91d92f8
    ./c_example(foo+0x14) [0x80485f8]
    ./c_example(bar+0x1f) [0x804861c]
    ./c_example(foobar+0x11) [0x804862f]
    ./c_example(main+0x2d) [0x804865e]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x144113]
    ./c_example() [0x8048551]
  Leak 3@0xb76fb6d0; leaked 16 bytes at position 0x91d9258
    ./c_example(bar+0x11) [0x804860e]
    ./c_example(foobar+0x11) [0x804862f]
    ./c_example(main+0x39) [0x804866a]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x144113]
   ./c_example() [0x8048551]
  Leak 4@0xb76fb6d0; leaked 64 bytes at position 0x91d9340
    ./c_example(foo+0x14) [0x80485f8]
    ./c_example(bar+0x1f) [0x804861c]
    ./c_example(foobar+0x11) [0x804862f]
    ./c_example(main+0x39) [0x804866a]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x144113]
    ./c_example() [0x8048551]
  fredrik@ubuntu-01:~/Development/leakfinder$
  Now the method name is included and that makes it a whole lot easier to read, and while this works for C++ programs as well their stacktraces are still a bit messy because of name mangling, but still very much readable when compiled with -rdynamic, as seen below in the output from cpp_example (also included in the download);

 Collapse | Copy Code
  fredrik@ubuntu-01:~/Development/leakfinder$ ./cpp_example
  leakfinder C++ thread example app
  This application is expected to leak
  leakfinder detected that 4 out of 5 allocations was not released.
  Leak 1@0xb77e66d0; leaked 4 bytes at position 0x8e79020
    /usr/lib/i386-linux-gnu/libstdc++.so.6(_Znwj+0x27) [0x2f19d7]
    ./cpp_example(_ZN10my_class_aC1Ev+0x12) [0x8048c64]
    ./cpp_example(_ZN10my_class_bC1Ev+0x11) [0x8048ce9]
    ./cpp_example(main+0x5f) [0x8048b97]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x346113]
    ./cpp_example() [0x8048a81]
  Leak 2@0xb77e66d0; leaked 4 bytes at position 0x8e79108
    /usr/lib/i386-linux-gnu/libstdc++.so.6(_Znwj+0x27) [0x2f19d7]
    ./cpp_example(_ZN10my_class_b3fooEv+0x12) [0x8048caa]
    ./cpp_example(_ZN10my_class_b3barEv+0x11) [0x8048cc1]
    ./cpp_example(_ZN10my_class_b6foobarEv+0x11) [0x8048cd5]
    ./cpp_example(main+0x6b) [0x8048ba3]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x346113]
    ./cpp_example() [0x8048a81]
  Leak 3@0xb77e66d0; leaked 4 bytes at position 0x8e791f0
    /usr/lib/i386-linux-gnu/libstdc++.so.6(_Znwj+0x27) [0x2f19d7]
    ./cpp_example(_ZN10my_class_b3fooEv+0x12) [0x8048caa]
    ./cpp_example(main+0x77) [0x8048baf]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x346113]
    ./cpp_example() [0x8048a81]
  Leak 4@0xb77e66d0; leaked 1 bytes at position 0x8e79250
    /usr/lib/i386-linux-gnu/libstdc++.so.6(_Znwj+0x27) [0x2f19d7]
    ./cpp_example(_Z12cpp_functionv+0x12) [0x8048b26]
    ./cpp_example(c_function+0xb) [0x8048b36]
    ./cpp_example(main+0x7c) [0x8048bb4]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x346113]
    ./cpp_example() [0x8048a81]
  fredrik@ubuntu-01:~/Development/leakfinder$
Points of interest

  Like I stated at the beginning of the article, this is not an attempt at a finished leak detection product but an explanation of how such a product can be   created. The observant reader will have realised that the implementation included with this article is lacking in many areas, it does not explicily cater for (for example) calloc and that using a std::vector to store the allocation_info objects results in a linear performance penalty on the lookups.

  Regardless of this, I hope the article has provided a certain amount of insight into how leaks can be spotted in a non-intrusive way (in the sense that the application code does not need to be instrumented or otherwise augmented). 
And weirdly enough, the Code Project article submission wizard does not allow me to upload .tar files, so if you want one of those instead; you can get it from here (the allocation_info.cpp file is broken but I'll fix that at a later time, the .zip file is correct); https://sites.google.com/site/fredrikbornander/Home/leakfinder.tar?attredirects=0&d=1 

 

  Any comments are most welcome.

分享到:
评论

相关推荐

    windows下c++内存泄露检测工具使用方

    ### Windows 下 C++ 内存泄露检测工具使用详解 在 Windows 平台下进行 C++ 开发时,内存管理是一项非常重要的任务。由于 C++ 语言本身的特性,开发者需要手动管理内存分配与释放,这就很容易导致内存泄露的问题。...

    C++内存泄露检测器

    在C++编程中,内存管理是一项关键任务,而内存泄漏是开发者经常遇到的挑战。内存泄漏指的是程序在分配了内存后未能正确释放,导致这部分内存无法再被程序使用,随着时间推移,大量的内存泄漏可能会耗尽系统资源,...

    有效的C++内存泄露检测方法.pdf

    ### 有效的C++内存泄露检测方法 #### 摘要 本文提出了一种针对C++程序的高效内存泄漏检测方法。该方法通过深入分析内存泄漏现象,并重新实现了动态内存分配和释放函数,能够准确记录每次内存分配的具体位置,并对...

    C++内存泄漏检测原理+代码

    本文档将深入探讨C++内存泄漏检测的原理,并提供相关的代码示例。 首先,我们需要理解什么是内存泄漏。在C++中,程序员需要手动分配和释放内存。当动态分配的内存不再使用但没有被正确释放时,就会发生内存泄漏。...

    Linux 平台中调试 C-C++ 内存泄漏方法

    在 Linux 平台中调试 C-C++ 内存泄漏方法

    C++内存泄露的文档和代码

    ### C++内存泄露详解 #### 一、引言 在C++编程中,内存管理是一项基本而重要的技能。良好的内存管理不仅能够提升程序性能,还能避免各种潜在的问题,如内存泄漏。本文将从C++内存泄露的基础概念入手,结合具体的...

    C++内存泄露检测原理、源码及详解

    本篇文章将深入探讨C++内存泄露的检测原理,提供相应的源码,并阐述如何实现跨平台检测。 内存泄露检测主要分为静态分析和动态分析两种方法。静态分析是在编译阶段进行的,通过检查源代码来查找可能导致内存泄露的...

    C++内存泄漏检测工具

    内存泄漏是C++程序员经常会遇到的问题,它发生在程序动态分配了内存但未能正确释放时。随着时间的推移,这些未释放的内存会逐渐积累,最终可能导致程序崩溃或者性能急剧下降。因此,有效地检测和解决内存泄漏是确保...

    介绍几款 C/C++内存泄漏检测工具.帮程序员擦屁股用

    本文将详细介绍几款实用的C/C++内存泄漏检测工具,帮助程序员有效地找出并修复内存泄漏。 1. **AddressSanitizer (ASan)** AddressSanitizer是一个由Google开发的高效内存错误检测工具,包括检测堆、栈、全局变量...

    Visual C++内存泄露检测工具

    Visual Leak Detector是一款免费的、健全的、开源的Visual C++内存泄露检测系统。相比Visual C++自带的内存检测机制,Visual Leak Detector可以显示导致内存泄露的完整内存分配调用堆栈。 下载Visual Leak Detector...

    LeakTracer C++ 内存泄漏检查工具

    LeakTracer是一款专为C++程序设计的内存泄漏检测工具,主要应用于Linux、Solaris和HP-UX等操作系统环境。内存泄漏是编程过程中常见的问题,尤其是对于动态内存管理的语言如C++,它可能导致程序运行效率下降,甚至...

    几个内存泄漏的例子

    内存泄漏是C++编程中一个严重的问题,它指的是程序在申请内存后,无法释放已申请的内存空间,一次小的内存泄漏可能看似无害,但随着时间推移,大量的内存泄漏会消耗掉系统的可用内存,导致性能下降甚至系统崩溃。...

    浅谈C_C++内存泄漏及其检测工具

    在C/C++中,内存泄漏尤其指的是堆内存泄漏,因为堆内存是需要程序员手动管理的,而栈内存会在函数调用结束时自动释放。 C/C++程序员通常使用new/delete运算符和malloc/free函数来分配和释放堆内存。如果程序在申请...

    最好用的内存泄漏分析工具 ------ tMemMonitor (TMM)

    tMemMonitor(TMM)是一款运行时C/C++内存泄漏分析工具,其检测结果专业、准确,操作却极其简单,可以帮助C/C++程序员迅速解决内存泄漏。TMM中引入GC机制,内存泄露检测准确率可达100%,无需内存快照,不影响目标...

    C++内存管理(内存管理、内存泄漏、内存回收)

    "C++内存管理" ..."C++内存管理"资源摘要信息是C++内存管理的核心要素,它涵盖了内存管理的重要性、内存分配方式、内存泄漏和内存回收等方面的知识点,为读者提供了一个系统的C++内存管理知识框架。

    C++内存泄露检查指导.doc

    《C++内存泄露检查指导》 引言: 内存泄露是C++编程中常见的问题,它会导致程序性能下降,甚至在严重情况下使程序崩溃。本文旨在为C++开发者提供一套全面的内存泄露检查与预防策略,帮助他们理解内存泄露的本质,...

    一个跨平台的 C++ 内存泄漏检测器

    一个跨平台的C++内存泄漏检测器就是为了帮助开发者识别并修复这类问题而设计的工具。本文将深入探讨内存泄漏的基本概念、为何需要跨平台支持以及如何使用dbg_new这样的内存泄漏检测器。 首先,让我们理解什么是内存...

    C++内存泄漏演示程序

    C++编程实现内存泄漏演示(win7以下的系统请谨慎运行),编译运行后可在资源管理器中看到该程序占用的内存在以一定的速度增长

    一种有效的C++内存泄漏自检测方法.pdf

    ### 一种有效的C++内存泄漏自检测方法 #### 摘要 本文介绍了一种针对C++编程语言中动态内存管理的有效自检测方法,旨在帮助开发者预防和检测内存泄漏问题。该方法通过构建一个特定的对象行为结构模型来监控内存的...

    C++内存泄露检查方法

    ### C++内存泄露检查方法详解 #### 一、引言 在软件开发中,内存管理是确保程序稳定性和性能的关键因素之一。对于使用C++编写的程序而言,内存泄露问题尤为常见,它不仅会导致程序运行效率降低,还可能引发程序...

Global site tag (gtag.js) - Google Analytics