您的位置:首页 > 编程语言 > C语言/C++

Typical memory leak (C++中典型的内存泄露)

2016-02-19 09:46 603 查看


Definition

Memory Leak: leak on the heap, memory allocation during runtime

1.Frequent Memory Leak: a code include memory leak is used frequently (most dangerous but relatively easy to find)

2.Occasional Memory Leak: memory leak happens in specific occasion (hard to find)

3.One-Time Memory Leak: only leak once, like in a singleton class (not that dangerous)

4.Implicit Memory Leak: always allocate memory during the runtime and only free memory until exit (hard to find and dangerous, may hold too much memory and lead to crush )


Examples


1.Forget to free/delete

void func()
{
char *oldString = "Old String";
char* newStrig = strdup(oldString);  //be careful with c lib-functions which alloc memory inside
char *textString = malloc(128*sizeof(char));
ClassTypeA *ptr = new ClassTypeA;
return;
}


Be careful with logic branches

BassClass * obj = new BaseClass;
if(test something)
return;
else if (test something)
do something;
else
do something;
delete obj;
return;


2.Careful with Inheritance, polymorphism

BaseClass* obj_ptr = new DerivedClass;
delete obj_ptr;

/*If you are counting on the destructor to delete memory allocated in the constructor beware of this mistake as it will cause a memory leak. */
/*Use a virtual destructor to avoid this problem.*/


3.Pointer re-assignment error

char *a = malloc(128*sizeof(char));
char *b = malloc(128*sizeof(char));
b = a;
free(a);
free(b); // will not free the pointer to the original allocated memory.


4.[b]Default copy constructor may not give correct results[/b]

ClassA& operator=(const ClassA& right_hand_side);
/*sallow copy, deep copy?*/
/*Memory allocated by copy constructors for pointer duplication. Check in destructor and delete if necessary. Memory allocated in passing class by value which invokes copy constructor. Also beware, the default copy constructor may not give you the results you want especially when dealing with pointers as the default copy constructor has no knowledge of how to copy the contents of what the pointer points to. To prohibit the use of the default copy constructor define a null assignment operator. And when there is allocation in class, define your own destructor*/

class GCharacter //Game Character
{
private:
std::string name;
int capacity;   //the capacity of our tool array
int used;       //the nr of elements that we've actually used in that tool array
std::string* toolHolder; //string pointer that will be able to reference our ToolArray;

public:
static const int DEFAULT_CAPACITY = 5;
//Constructor
GCharacter(std::string n = "John", int cap = DEFAULT_CAPACITY)
:name(n), capacity(cap), used(0), toolHolder(new string[cap])
{
}
}

int main()
{
GCharacter gc1("BoB", 5);
GCharacter gc2("Terry", 5);
gc2 = gc1;
GCharacter gc3 = gc1;
return 0;
}


5. Do not rely on STL containers

vector<Object *> objects;
for (int i=0;i <10; i++)
{
Object * obj = new Object;
objects.push_back(obj);
}
//do something with objects ....
objects.clear();
return;

Yes, stl containers will call destruct functions.

But in this case, the container dose not free any memory.
vector <T> objects;
//when clear object in vector, the vector will call the destructor of T in this way
*T->~T();


6. Implicit Memory Leak: free memory as soon as you don't need it(or need so large)

another stl example:

stl containers always know how and when to expand itself, but they never know when to shrink itself.
{
vector<int> vec;
for(int64_t i=0; i<1000000000000000000; i++)
vec.push_back(1);
//do something
vec.clear(); /*don't need it anymore*/
//do a lot of things, maybe online service, never need to stop until next release
}

then the 1000000000000000000*sizeof(int) memory will hold forever.
//if you don't need it
vector<int>().swap(vec) //instead of clear

//if you want to shrink the container size
vector<int>(vec).swap(vec)


7. Implicit Memory Leak: heap fragmentation(impossible to be found by tools)

You think the code is memory leak free, but the memory usage always going up and then crush....

Applications that are free from memory leaks but perform dynamic memory allocation and deallocation frequently tend to show gradual performance degradation if they are kept running for long periods. Finally, they crash. Why is
this? Recurrent allocation and deallocation of dynamic memory causes the heap to become fragmented, especially if the application allocates small memory chunks (int, an 8 byte object etc.). A fragmented heap can have many free blocks, but these blocks are
small and non-contiguous.

imagine that you have a "large" (32 bytes) expanse of free memory:

----------------------------------


|                                |


----------------------------------


Now, allocate some of it (5 allocations):

----------------------------------


|aaaabbccccccddeeee              |


----------------------------------


Now, free the first four allocations but not the fifth:

----------------------------------


|              eeee              |


----------------------------------


Now, try to allocate 16 bytes. Oops, I can't, even though there's nearly double that much free.

On systems with virtual memory, fragmentation is less of a problem than you might think, because large allocations only need to be contiguous in virtual address space, not in physical address space. So in my example, if I had virtual memory
with a page size of 2 bytes then I could make my 16 byte allocation with no problem. Physical memory would look like this:

----------------------------------


| ffffffffffffffeeeeff           |


----------------------------------


whereas virtual memory (being much bigger) could look like this:

------------------------------------------------------...


|               eeeeffffffffffffffff


------------------------------------------------------...


The classic symptom of memory fragmentation is that you try to allocate a large block and you can't, even though you appear to have enough memory free. Another possible consequence is the inability of the process to release memory back to the OS (because there's
some object still in use in all the blocks it has allocated from the OS, even though those blocks are now mostly unused).

Method to avoid:

1.First of all, use dynamic memory as little as possible. In most cases, you can use static or automatic storage instead of allocating objects dynamically.

2.Secondly, try to allocate large chunks rather than small ones. For example, instead of allocating a single object, allocate an array of objects at once, and use these objects when they are needed.

(Like use reserve() for stl containers)

3. If all these tips don't solve the fragmentation problem, you should consider building a custom memory pool.


8. Implicit Memory Leak: memory not release to OS

When you call free() or delete(), it will NOT really release any memory back to OS. Instead, that memory is kept with the same process until it is terminated. However, this memory can be reused for any future allocations
by the same process.

documentation for libc's free:

Occasionally,
free
can actually return memory to the operating system and make the process smaller. Usually, all it can do is allow a later call to
malloc
to reuse the space. In the meantime, the space remains in your program as part
of a free-list used internally by
malloc
.

a little deeper by looking at other malloc/free family of functions and saw 'mallopt',
and that you can actually change the way malloc/free behave (especially if you're using GNU libc -- pointers about other platform implementations would be helpful). One option that is interesting to look at is M_TRIM_THRESHOLD which:

This is the minimum size (in bytes) of the top-most, releasable chunk that will cause
sbrk
to be called with a negative argument in order to return memory to the system.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: