LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 12-15-2005, 12:37 PM   #1
Thinking
Member
 
Registered: Oct 2003
Posts: 249

Rep: Reputation: 30
How to avoid Memory Leakage? (C/C++)


hiho@ll

is there a 100% way to avoid such leaks?
if yes, how does it work? any hints would be great
if not, how does the "not 100%" method work?

i know there are some methods to avoid this (reference counting, ...), so how they work with C/C++?

i could do a self-written malloc or free
but the most time i use "new Object()" and STL stuff like vector or string which doesnt really make it necessary to do a malloc by my own

1: any hints (not only some doc, but some code too) would be cool
2: my biggest problem will be, what if my project i'm currently working on, is getting released and some time later strange behaviour is reported (e.g. it needs much memory resource) and i don't know why?
anybody has an idea of "logging" so i can check, "ok, the most allocated object is xyz which has been allocated n times" (i would only need a hint where the leak could be)
3: i know dlopen and now i want to know if such function is available instead of the "new" keyword like this: void* instantiateObject(char *classname,...); /*... is an argument list for the constructor like a list for printf();*/

thx@ll
 
Old 12-15-2005, 12:52 PM   #2
sirclif
Member
 
Registered: Sep 2004
Location: south texas
Distribution: fedora core 3,4; gentoo
Posts: 192

Rep: Reputation: 30
i guess one "tip" would be to make sure your write destructor for any classes you write that allocate memory in the constructor.
 
Old 12-15-2005, 01:01 PM   #3
jonaskoelker
Senior Member
 
Registered: Jul 2004
Location: Denmark
Distribution: Ubuntu, Debian
Posts: 1,524

Rep: Reputation: 47
What works 100% is manually and correctly freeing allocated memory.

What also works is reference counting, if your object structures don't contain cycles. If they do contain cycles, try to break them up, make some references weak, or encapsulate the cycle in some class and break in the destructor of that class. shared_ptr from the boost library does the reference counting for you.

You may also want to override operator new and count each allocation (and possibly override operator delete--similarly for the array-operators--to see if any object is leaked). Alternatively, put the allocation counting in an allocator class.

hth --Jonas
 
Old 12-15-2005, 01:28 PM   #4
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
this is what i use to track any leaks, but there seems to be a problem with including it in header files and only seems to work if include in the .cpp file. dont know why?

anyway I'm some peeps are going to say theres something wrong with this lol.

also it checks if malloc failed, but doesnt do anything about it!

example of how i use it.

main.cpp
Code:
#include <memory_check.h>

int main(int argc, char **argv)
{
    //create the singleton class
    Memory* memory_ptr = Memory::manager();
    //create some memory
    int* a = new int;
    int* b = new int;
    //recover a
    delete a;
    //delete the manager
    delete memory_ptr;
    
    return 0;
}
this should create a memory leak file with the line and file of the new call.



Code:
#define _MEMORY_CHECK_H_

#include <stdlib.h>
#include <malloc.h>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

typedef struct 
{
	void* address;
	unsigned int size;
	std::string file;
	int line;
} memory_info;

__inline string cstring2string(char* c_string)
{
	string message;
	for(int i=0; i<=(int)strlen(c_string); i++)
	{ message = message  + c_string[i]; }

	return message;
}

class Memory
{
public:
	static Memory* manager()
	{
		static Memory* m_manager = 0;
		if (! m_manager)
	          { m_manager = new(Memory); }
		return m_manager;
	}

	~Memory(){save_to_file(); }


	void add(unsigned int size, char* file, int line, void* address)
	{
		memory_info info;
		info.size = size;
		info.file = cstring2string(file);
		info.line = line;
		info.address = address;
		ptr_vector.push_back(info);
	}	

	void remove(void* address)
	{
		for(ptr_iter = ptr_vector.begin(); ptr_iter != ptr_vector.end(); ++ptr_iter)
		{
			if(ptr_iter->address == address)
			{
				ptr_vector.erase(ptr_iter);
				return;
			}
		}
	}

	void save_to_file()
	{
		char file_name[]="memory_leaks.txt";
		out.open( file_name, std::ios::out /*| ios::app*/ );

		if(!out.is_open())
			{cout <<"ERROR\ncould not open file " <<file_name <<endl;}
		else 
		{
			for(ptr_iter = ptr_vector.begin(); ptr_iter != ptr_vector.end(); ++ptr_iter)
			{
				out <<"address:" <<ptr_iter->address <<" "
					<<"size:" <<ptr_iter->size 
					<<"\n\tfile:" <<ptr_iter->file <<" "
					<<"\n\tline:" <<ptr_iter->line <<" " <<"\n";
			}
			out <<"\0";
			out.close();
		}
	}

private:
	std::ofstream out;
	Memory(){;}
	std::vector<memory_info> ptr_vector;
	std::vector<memory_info> ::iterator ptr_iter;
};

inline void __cdecl operator delete(void* ptr)
{
	Memory::manager()->remove(ptr);
	free(ptr);
}

inline void * __cdecl operator new(unsigned int size,char* file, int line)
{
	void *ptr = (void *)malloc(size);
	if(ptr == 0)
	{
		std::cout <<"memory could not be allocated!\n";
	}
		Memory::manager()->add(size,file,line,ptr);
	return ptr;
}



//some macro magic to make the new call give its line and file
#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW


#endif //_MEMORY_CHECK_H_

i should add that i use this code to test parts of code and not full apps.

Last edited by dmail; 12-15-2005 at 01:39 PM.
 
Old 12-15-2005, 01:32 PM   #5
cyent
Member
 
Registered: Aug 2001
Location: ChristChurch New Zealand
Distribution: Ubuntu
Posts: 398

Rep: Reputation: 87
First, a 100% way of preventing memory leak would be equivalent to the halting problem. (ie. Provably impossible)

Secondly the best design principle is to consider carefully who sould own and be responsible for the allocation and deallocation of the data. The Law of Demeter can be a guide in deciding this, so can the notion of object lifetimes. (ie. The owner must live as least as long as any user of the data)

Thirdly, most practically, use valgrind.

It is very very good.
 
Old 12-16-2005, 05:02 AM   #6
Thinking
Member
 
Registered: Oct 2003
Posts: 249

Original Poster
Rep: Reputation: 30
the idea with overriding operators seems good
but i think i'll have a look @ http://www.hpl.hp.com/personal/Hans_Boehm/gc/

@dmail
thx for your code
i think i'll use some parts for the beginning

thx@ll
 
Old 12-16-2005, 10:56 PM   #7
llmmix
Member
 
Registered: Jun 2005
Posts: 73

Rep: Reputation: 15
not sure about %100 But,

1.try not to use memory allocation as possible.

2. ask gnome developer who digging 2.14

as you know, that's why .net and java born.

pragmatic programmer
http://www.amazon.com/exec/obidos/tg...1622X?v=glance
 
Old 12-17-2005, 04:12 AM   #8
knownrider
LQ Newbie
 
Registered: Sep 2005
Distribution: Ubuntu, but always looking for the next great distro
Posts: 1

Rep: Reputation: 0
Quote:
Originally Posted by cyent
Thirdly, most practically, use valgrind.

It is very very good.
I agree.
valgrind can usually be downloaded with your gcc/g++ compiler packages.
For example, in Ubuntu, you'd just: apt-get install valgrind

It's a great tool, specifically for finding memory leaks.
 
Old 12-17-2005, 09:22 AM   #9
clinux_rulz
Member
 
Registered: Nov 2005
Distribution: Gentoo
Posts: 51

Rep: Reputation: 16
I'm not sure exactly what you are after. You said some documentation or some code would be cool.

I have here some code for automatic reference counting in c++, that works for objects that inherit the Object class, it is far from complete, but it makes a good example. Just remember when you are using reference counting and you have a child class referencing a perent class and that parent class referencing that same child class, make the child class using a weak reference (just a pointer), that way memory leaks will not occur from circular dependancies.

Code:
//////////////////////////////////////////////////////////////////////////////
// $Revision$
// $Id$
//////////////////////////////////////////////////////////////////////////////

#ifndef _OBJECT_H
#define _OBJECT_H

// Everything here is inline, because it is called alot.
class Object {
  public:
    //Object(): mpCount(new int(1)) {}
    //virtual ~Object() { delete mpCount; }

    //virtual void Ref() const { ++*mpCount; }
    //virtual void Unref() const { if (--*mpCount == 0) delete this; }
    //virtual int refCount() const { return *mpCount; }

    Object(): mCount(1) {}
    virtual ~Object() {}
    
    virtual void Ref() const { ++mCount; }
    virtual void Unref() const { if (--mCount == 0) { delete this; } }
    virtual int refCount() const { return mCount; }
    
  private:
    //int* mpCount;
    mutable int mCount;
};

#endif // _OBJECT_H

//////////////////////////////////////////////////////////////////////////////
// $Log$
//////////////////////////////////////////////////////////////////////////////

// vim:ts=2:sw=2:sts=2:et
Code:
//////////////////////////////////////////////////////////////////////////////
// $Id$
// $Revision$
//////////////////////////////////////////////////////////////////////////////

#ifndef _REF_H
#define _REF_H

template <class TObject>
class Ref {
  private:
    TObject* mpObject;
  public:
    Ref(): mpObject(0) {}
    Ref(TObject* pObject): mpObject(0) { *this = pObject; }
    Ref(Ref const& ref): mpObject(0) { *this = ref; }
    Ref(TObject& object): mpObject(0) { *this = object; }
    ~Ref() { if (mpObject != 0) mpObject->Unref(); }
    
    //-------------------------------------------------------------------------
    
    Ref<TObject>& operator=(TObject* pObject)
    {
      if (mpObject != 0) {
        if (mpObject->refCount() == 1) {
          mpObject->Unref();
          mpObject = 0;
        } else {
          mpObject->Unref();
        }
      }
      mpObject = pObject;
      return *this;
    }
    
    //-------------------------------------------------------------------------
    
    Ref<TObject>& operator=(Ref const& ref)
    {
      if (mpObject != 0) {
        if (mpObject->refCount() == 1) {
          mpObject->Unref();
          mpObject = 0;
        } else {
          mpObject->Unref();
        }
      }
      if (ref.mpObject != 0) {
        ref.mpObject->Ref();
      }
      mpObject = ref.mpObject;
      return *this;
    }
    
    //-------------------------------------------------------------------------
    
    Ref<TObject>& operator=(TObject& object)
    {
      if (mpObject != 0) {
        if (mpObject->refCount() == 1) {
          mpObject->Unref();
          mpObject = 0;
        } else {
          mpObject->Unref();
        }
      }
      object.Ref();
      mpObject = &object;
      return *this;
    }
    
    //-------------------------------------------------------------------------
    
    TObject* operator->()
    {
      return mpObject;
    }
    
    //-------------------------------------------------------------------------
    
    TObject const* operator->() const
    {
      return mpObject;
    }
    
    //-------------------------------------------------------------------------
    
    TObject& operator*()
    {
      return *mpObject;
    }
    
    //-------------------------------------------------------------------------
    
    TObject const& operator*() const
    {
      return *mpObject;
    }
    
    //-------------------------------------------------------------------------
    
    bool operator==(TObject const& object) const
    {
      return mpObject == &object;
    }
    
    //-------------------------------------------------------------------------
    
    bool operator==(TObject const* pObject) const
    {
      return mpObject == pObject;
    }
    
    //-------------------------------------------------------------------------
    
    bool operator==(Ref<TObject> const& ref) const
    {
      return mpObject == ref.mpObject;
    }
    
    //-------------------------------------------------------------------------
    
    bool isNotNull() const
    {
      return mpObject != 0;
    }
    
    //-------------------------------------------------------------------------
    
    bool isNull() const
    {
      return mpObject == 0;
    }
    
    //-------------------------------------------------------------------------
    
    void MakeNull() {
      if (mpObject != 0) {
        mpObject->Unref();
        mpObject = 0;
      }
    }
};

#endif // _REF_H

//////////////////////////////////////////////////////////////////////////////
// $Log$
//////////////////////////////////////////////////////////////////////////////

// vim:ts=2:sw=2:sts=2:et
And to use it is simple.

Code:
class A: virtual public Object {
 . . . Some stuff . . .
};

int main()
{
  A B;
  Ref<A> rA = new A;
  Ref<A> rA2 = A;
  Ref<A> rA3 = B;
  . . . Some more stuff . . .
  return 0;
}
There is no need for Unref() or delete in the sample code above, the Ref<T> class template does everything for you through the Object class. Note: B in the above example uses stack space and is not accidently freed, because Ref<T> addeds an extra reference to make sure the reference count does not hit zero.

Last edited by clinux_rulz; 12-17-2005 at 09:33 AM. Reason: slashes the wrong way in code blocks
 
Old 12-18-2005, 01:31 PM   #10
cyent
Member
 
Registered: Aug 2001
Location: ChristChurch New Zealand
Distribution: Ubuntu
Posts: 398

Rep: Reputation: 87
See my next post for an example of what can go wrong with ref counted pointers.
 
Old 12-18-2005, 01:31 PM   #11
cyent
Member
 
Registered: Aug 2001
Location: ChristChurch New Zealand
Distribution: Ubuntu
Posts: 398

Rep: Reputation: 87
See my previous post for an example of what can go wrong with ref counted pointers.
 
Old 12-19-2005, 10:33 AM   #12
clinux_rulz
Member
 
Registered: Nov 2005
Distribution: Gentoo
Posts: 51

Rep: Reputation: 16
cyent has a point in his/her last two posts, this problem is mainly avoided by using weak references.

class PhysicsSystem {
public:
. . . BLAH BLAH BLAH . . .
private:
list<Ref<PhysicsObject> > mPhysicsObjects;
};

class PhysicsObject {
public:
. . . BLAH BLAH BLAH . . .
private:
PhysicsSystem* mpParent;
};

In the two examples any of the mPhysicsObjects are referenced to a PhysicsObject, where as each of the PhysicsObject's mpParent(s) are weakly referenced back to the PhysicsSystem it belongs too.

The type PhysicsSystem* is a weak reference, because it is a pointer without any reference counting.

The type Ref<PhysicsObject> is a actual reference, that will do reference counting, and hits zero and deletes itself once nobody is using the PhysicsObject that it references anymore.

Sometimes a system can be too complex to correctly implement with a combination of References and Weak References, in which case Garbarge Collection is a ok idea. Garbages Collection is faster than reference counting, because it does not have to update a counter, and because it does not have to free any memory until any criterion to Collect the Garbage has been meet.

Most the time reference counting should be ok, but do not over use it. Only use it in areas which it is helpful, do not use it for everything. If you have an instance of an object that is only used by one piece of code (like a single class), then do not use reference couning. But if you have an object that a heap of classes may contain, and the order of destruction of the classes is not predetermined or can happen in any order, then do use reference counting.

When using reference counting be carefull to make sure there are no circular dependances, and eleminate any circular dependances with a weak reference. E.g. a doubling linked list with references for the nodes (maybe because the nodes can be spliced together in a specialised list, mimicing a tree), then make the nodes have a Reference to the next node and just a Weak reference to the previous node. Then when you are done unreference the first node and what them all blow up like a chain reaction, until you list is freed.

Unfortunatly if you were implementing a circular list you would have a circular dependance still event with the implementation described in the previos paragraph. And in this case you might now want to use Reference Counting or just simply have a flag at the end of the list where the tail joins to the front so you can double unreference.
 
Old 12-19-2005, 10:54 AM   #13
clinux_rulz
Member
 
Registered: Nov 2005
Distribution: Gentoo
Posts: 51

Rep: Reputation: 16
If you need a pointer to an object that will automatically free itself, and is only needed by one section or piece of code, then you can use Auto Pointers.

Code:
template <class T>
class AutoPtr {
  public:
    AutoPtr(): mpObject(0) {}
    AutoPtr(T* pObject): mpObject(pObject) {}
    ~AutoPtr()
    {
      if (mpObject != 0) { delete mpObject; }
    }

    AutoPtr& operator=(T* pObject)
    {
      if (mpObject != 0) { delete mpObject; }
      mpObject = pObject;
      return *this;
    }

    // AND implement the other stuff pointers can do, like comparison operators.
    bool operator==(T* pObject) const
    {
       return mpObject == pObjecy;
    }

    bool operator==(AutoPtr<T> const& autoPtr) const
    {
      return mpObject == autoPtr.mObject;
    }

    bool operator!=   . . . BLAH BLAH BLAH . . .

    . . . BLAH BLAH BLAH . . .

  private:
    T* pObject;
};
Auto pointer you can just treat as pointers, plus unlike normal pointers you can still easly free there memory in the point of an exception, almost like a stacky dynamic memory type of thing.

One problem is that if you wanted more that the one copy of this object, you would have to make more exact copies instead of using the same one.

AutoPtr<Crap>* pMyCrap = new Crap;
AutoPtr<Crap>* pACopyOfMyCrap = new Crap(*pMyCrap);

So on the down side it uses more memory, but on the up side no memory leaks.
Sometimes this can be just as bad as stack variables, and your just better of using them.

AutoPtr(s) are good when you do not have the information to create the object until a function is called that supplies the information. Sort of like delayed construction. Like a render function for a 3d model might supply the plugin for the video at render time, but not at the loading time of the 3d model, so the loading of the textures can be delayed until the video plugin can allocate a texture from video memory to give to the 3d model to use for rendering, then in the next render the texture is no longer needed to be allocated.
 
Old 12-21-2005, 12:44 AM   #14
Thinking
Member
 
Registered: Oct 2003
Posts: 249

Original Poster
Rep: Reputation: 30
that's a hard topic
i had to read it twice to understand ;-)

but how does garbace collection work?
are AutoPtr the only way in C++?

i mean i understand how php or java garbace collection may work
those languages are interpreted so it's more or less easy
but in C/C++ it seems a challenge to do it correctly
 
Old 12-23-2005, 06:42 PM   #15
clinux_rulz
Member
 
Registered: Nov 2005
Distribution: Gentoo
Posts: 51

Rep: Reputation: 16
AutoPtrs are not the only way!!!

Garbage collection works too, but it is a fair amount of work. It involves creating a seperate thread on low priority to check the memory once in a while, and you also must overload your new, new[], delete, delete[] operators, and your malloc() and free() functions, if you entend to use them as well.

To create the platform independand thread for the garbage collection you can use SDL_Thread from the SDL library.

When memory is allocated, extra space for a void* should be allocated as well, so that all allocated objects can be linked together in a forward singular link list fasion. Also you should store the location of the head and the tail of the list as static void pointers in the source file for garbage collection. When new memory is allocated it must be linked on the tail, and when the garbage is collected all the memory should be freed following from the head node onwards.

Also add a dummy class with a dummy static object in your garbage collection source to make sure the all the garbage is collected, so that the garbage is collected before your application terminates.

Code:
class _ {
  public:
    _() {}
    _() { Garbage::Collect(); }
} static __;
The actual implementation of all this I do not feel like doing now. Hopefully someone will implement this below my post.

Last edited by clinux_rulz; 12-24-2005 at 11:06 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Severe memory leakage! (Kernel or KDE) MBH Linux - General 1 07-08-2004 08:34 AM
Laptops to avoid?? morrolan Linux - Laptop and Netbook 4 01-24-2004 04:59 PM
Memory Leakage Problem (Pls Help me out !! ) Urgent!!! amit4linux Red Hat 0 11-18-2003 10:40 PM
Can I get a HOW-TO avoid MCSE jdc2048 General 18 06-23-2003 03:35 AM
Help!?! RH 8 Memory Mapping -High Memory-Virtural Memory issues.. Merlin53 Linux - Hardware 2 06-18-2003 04:48 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:19 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration