views:

519

answers:

6

Hy all,

I believe that the following piece of code is generating memory leak?

    /* External function to dynamically allocate a vector */
    template <class T>
            T *dvector(int n){
            T *v;

            v = (T *)malloc(n*sizeof(T));

            return v;
    }


    /* Function that calls DVECTOR and, after computation, frees it */
    void DiscontinuousGalerkin_Domain::computeFaceInviscidFluxes(){
            int e,f,n,p;
            double *Left_Conserved;

            Left_Conserved = dvector<double>(NumberOfProperties);

            //do stuff with Left_Conserved
            //

            free(Left_Conserved);

            return;
    }

I thought that, by passing the pointer to DVECTOR, it would allocate it and return the correct address, so that *free(Left_Conserved)* would successfully deallocate. However, it does not seem to be the case.

NOTE: I have also tested with new/delete replacing malloc/free without success either.

I have a similar piece of code for allocating a 2-D array. I decided to manage vectors/arrays like that because I am using them a lot, and I also would like to understand a bit deeper memory management with C++.

So, I would pretty much like to keep an external function to allocate vectors and arrays for me. What's the catch here to avoid the memory leak?

EDIT

I have been using the DVECTOR function to allocate user-defined types as well, so that is potentially a problem, I guess, since I don't have constructors being called.

Even though in the piece of code before I free the Left_Conserved vector, I also would like to otherwise allocate a vector and left it "open" to be assessed through its pointer by other functions. If using BOOST, it will automatically clean the allocation upon the end of the function, so, I won't get a "public" array with BOOST, right? I suppose that's easily fixed with NEW, but what would be the better way for a matrix?

It has just occurred me that I pass the pointer as an argument to other functions. Now, BOOST seems not to be enjoying it that much and compilation exits with errors.

So, I stand still with the need for a pointer to a vector or a matrix, that accepts user-defined types, that will be passed as an argument to other functions. The vector (or matrix) would most likely be allocated in an external function, and freed in another suitable function. (I just wouldn't like to be copying the loop and new stuff for allocating the matrix everywhere in the code!)

Here is what I'd like to do:

    template <class T>
    T **dmatrix(int m, int n){
            T **A;

            A = (T **)malloc(m*sizeof(T *));
            A[0] = (T *)malloc(m*n*sizeof(T));

            for(int i=1;i<m;i++){
                    A[i] = A[i-1]+n;
            }

            return A;
    }


    void Element::setElement(int Ptot, int Qtot){

            double **MassMatrix;

            MassMatrix = dmatrix<myT>(Ptot,Qtot);

            FillInTheMatrix(MassMatrix);

            return;
    }
A: 

I don't see memory leak in this code.

If you write programs on c++ - use new/delete instead malloc/free.

For avoid possible memory leaks use smart pointers or stl containers.

bb
And make sure to use delete [] for arrays. That's one reason I like STL containers: fewer easy ways to mess up big.
David Thornley
+1  A: 

No, as long as you aren't doing anything drastic between the call to your dvector template and the free, you aren't leaking any memory. What tells you there is a memory leak?

May I ask, why you chose to create your own arrays instead of using STL containers like vector or list? That'd certainly save you a lot of trobule.

dirkgently
At code execution command top shows allocated memory growing indefinitely! When I comment all memory operations within DiscontinuousGalerkin_Domain::computeFaceInviscidFluxes(), memory stops leaking.Well, and I didn't know vector at all. Is it possible to create 2D arrays with it?
Biga
@Biga: A vector<double> is like a 1D array of doubles, vector< vector<double> > is a 2D array and so on ...
dirkgently
The result for that command is addressed as ARRAY[i][j]? And what if "i" and "j" spans different dimensions?
Biga
@Biga: Since vectors are implemented as arrays you can use the indexing notation. However, this is not valid for other containers.
dirkgently
+7  A: 

There is no memory leak there, but you should use new/delete[] instead of malloc/free. Especially since your function is templated.

If you ever want to to use a type which has a non-trivial constructor, your malloc based function is broken since it doesn't call any constructors.

I'd replace "dvector" with simply doing this:

void DiscontinuousGalerkin_Domain::computeFaceInviscidFluxes(){
        double *Left_Conserved = new double[NumberOfProperties];

        //do stuff with Left_Conserved
        //

        delete[] Left_Conserved;
}

It is functionally equivalent (except it can call constructors for other types). It is simpler and requires less code. Plus every c++ programmer will instantly know what is going on since it doesn't involve an extra function.

Better yet, use smart pointers to completely avoid memory leaks:

void DiscontinuousGalerkin_Domain::computeFaceInviscidFluxes(){
        boost::scoped_array<double> Left_Conserved(new double[NumberOfProperties]);

        //do stuff with Left_Conserved
        //
}

As many smart programmers like to say "the best code is the code you don't have to write"

EDIT: Why do you believe that the code you posted leaks memory?

EDIT: I saw your comment to another post saying

At code execution command top shows allocated memory growing indefinitely!

This may be completely normal (or may not be) depending on your allocation pattern. Usually the way heaps work is that they often grow, but don't often shrink (this is to favor subsequent allocations). Completely symmetric allocations and frees should allow the application to stabilize at a certain amount of usage.

For example:

while(1) {
    free(malloc(100));
}

shouldn't result in continuous growth because the heap is highly likely to give the same block for each malloc.

So my question to you is. Does it grow "indefinitely" or does it simply not shrink?

EDIT:

You have asked what to do about a 2D array. Personally, I would use a class to wrap the details. I'd either use a library (I believe boost has a n-dimmentional array class), or rolling your own shouldn't be too hard. Something like this may be sufficient:

http://www.codef00.com/code/matrix.h

Usage goes like this:

Matrix<int> m(2, 3);
m[1][2] = 10;

It is technically more efficient to use something like operator() for indexing a matrix wrapper class, but in this case I chose to simulate native array syntax. If efficiency is really important, it can be made as efficient as native arrays.

EDIT: another question. What platform are you developing on? If it is *nix, then I would recommend valgrind to help pinpoint your memory leak. Since the code you've provided is clearly not the problem.

I don't know of any, but I am sure that windows also has memory profiling tools.

EDIT: for a matrix if you insist on using plain old arrays, why not just allocate it as a single contiguous block and do simple math on indexing like this:

T *const p = new T[width * height];

then to access an element, just do this:

p[y * width + x] = whatever;

this way you do a delete[] on the pointer whether it is a 1D or 2D array.

Evan Teran
I also have an external function allocating a 2-D array, so that's why I didn't simply write it like you suggested. I was trying to avoid copying/pasting all the lines to dynamically allocate a 2-D array. Is there a smart way to do it?
Biga
It grows indefinitely and after a while, the PC hangs! (kinda freaking!)
Biga
You apparently have a memory leak, but it's not in the code you posted. That should work, although it's pretty brittle (for example, don't use it with user-defined types). Try converting all pointers to smart pointers, and use STL containers whenever possible.
David Thornley
I've been developing on Linux, and I am using Valgrind already. However, I may be stupid enough not to understand the output. Anyway, I get a clue from Valgrind that the above function was leaking...
Biga
It seems to be very common in C to program multi-arrays like that. The code I'm programming is academic and I would like to keep the two (or more) indices the more separated as possible to point out what each direction means.
Biga
+1  A: 

There is no visible memory leak, however there is a high risk for a memory leak with code like this. Try to always wrap up resources in an object (RAII). std::vector does exactly what you want :

void DiscontinuousGalerkin_Domain::computeFaceInviscidFluxes(){
        int e,f,n,p;
        std::vector<double> Left_Conserved(NumOfProperties);//create vector with "NumOfProperties" initial entries

        //do stuff with Left_Conserved
        //exactly same usage !
        for (int i = 0; i < NumOfProperties; i++){//loop should be "for (int i = 0; i < Left_Conserved.size();i++)" .size() == NumOfProperties ! (if you didn't add or remove any elements since construction
             Left_Conserved[i] = e*f + n*p*i;//made up operation
        }
        Left_Conserved.push_back(1.0);//vector automatically grows..no need to manually realloc
        assert(Left_Conserved.size() == NumOfProperties + 1);//yay - vector knows it's size
        //you don't have to care about the memory, the Left_Conserved OBJECT will clean it up (in the destructor which is automatically called when scope is left)
        return;
}

EDIT: added a few example operations. You really should read about STL-containers, they are worth it !
EDIT 2 : for 2d you can use :

std::vector<std::vector<double> >

like someone suggested in the comments. but usage with 2d is a little more tricky. You should first look into the 1d-case to know what's happening (enlarging vectors etc.)

qwerty
What about a 2-D array, like Properties[NumOfProperties][NumOfProperties]? Is there a a STD for that as well?
Biga
Is Left_Conserved a pointer, when allocated with vector?
Biga
A: 

What happens if you pass a negative value for n to dvector?

Perhaps you should consider changing your function signature to take an unsigned type as the argument:

template< typename T >
T * dvector( std::size_t n );

Also, as a matter of style, I suggest always providing your own memory release function any time you are providing a memory allocation function. As it is now, callers rely on knowledge that dvector is implemented using malloc (and that free is the appropriate release call). Something like this:

template< typename T >
void dvector_free( T * p ) { free( p ); }

As others have suggested, doing this as an RAII class would be more robust. And finally, as others have also suggested, there are plenty of existing, time-tested libraries to do this so you may not need to roll your own at all.

jwfearn
A: 

So, some important concepts discussed here helped me to solve the memory leaking out in my code. There were two main bugs:

  • The allocation with malloc of my user-defined types was buggy. However, when I changed it to new, leaking got even worse, and that's because one my user-defined types had a constructor calling an external function with no parameters and no correct memory management. Since I called that function after the constructor, there was no bug in the processing itself, but only on memory allocation. So new and a correct constructor solved one of the main memory leaks.

  • The other leaking was related to a buggy memory-deallocation command, which I was able to isolate with Valgrind (and a bit a patience to get its output correctly). So, here's the bug (and, please, don't call me a moron!):

    if (something){
            //do stuff
            return;    //and here it is!!!  =P
    }
    free();
    return;
    

And that's where an RAII, as I understood, would avoid misprogramming just like that. I haven't actually changed it to a std::vector or a boost::scoped_array coding yet because it is still not clear to me if a can pass them as parameter to other functions. So, I still must be careful with delete[].

Anyway, memory leaking is gone (by now...) =D

Biga