avaneev / biteopt

Derivative-Free Global Optimization Algorithm (C++, Python binding) - Continuous, Discrete, TSP, NLS, MINLP
MIT License
141 stars 9 forks source link

Memory leak #7

Closed dietmarwo closed 10 months ago

dietmarwo commented 10 months ago

In biteaux.h and biteopt.h there are "new" statements without corresponding "delete" statements.

For instance in void updateDims( const int aParamCount, const int M = 6, const int PopSize0 = 0 )

there is an deleteBuffers() call, but for "new CBiteOptWrap*[ OptCount ];" there seems no corresponding delete.

This leads to a memory leak in fcmaes (where BitOpt is called here https://github.com/dietmarwo/fast-cma-es/blob/master/_fcmaescpp/biteoptimizer.cpp)

Is there a way I can prevent this leak by adapting the calling code in biteoptimizer.cpp ?

avaneev commented 10 months ago

Please check the deleteBuffers() function in CBiteOptDeep - it does have the delete[] Opts; call.

dietmarwo commented 10 months ago

Isn't deleteBuffers() being called by the destructor ~CBiteOptDeep() automatically? See the example below, derived from your example, just calling the optimizer many times in a loop.

When executing the code, you see memory consumption of the process growing fast. How can I modify this code to avoid the memory leak?

#include <stdio.h>
#include "biteopt.h"

#if !defined( sqr )
#define sqr( x ) (( x ) * ( x ))
#endif // !defined( sqr )

class CTestOpt: public CBiteOpt {
public:
    CTestOpt() {
        updateDims(2);
    }

    virtual void getMinValues(double *const p) const {
        p[0] = -10.0;
        p[1] = -10.0;
    }

    virtual void getMaxValues(double *const p) const {
        p[0] = 10.0;
        p[1] = 10.0;
    }

    virtual double optcost(const double *const p) {
        const double x = p[0];
        const double y = p[1];

        return ( sqr( x + 2 * y - 7 ) + sqr(2 * x + y - 5));
    }
};

void test() {
    CBiteRnd rnd;
    rnd.init(1); // Needs to be seeded with different values on each run.

    CTestOpt opt;
    opt.init(rnd);

    for (int i = 0; i < 10000; i++) {
        opt.optimize(rnd);
        if (opt.getBestCost() < 0.1) {
            break;
        }
    }
}

int main() {
    for (int i = 0; i < 100000000; i++)
        test();
    return (0);
}
avaneev commented 10 months ago

Thanks for bringing this to my attention. I've fixed memory leaks issue, updated repo.

dietmarwo commented 10 months ago

Thks, I recommend https://valgrind.org/docs/manual/quick-start.html#quick-start.prepare under Linux to check for this kind of issue. You get complete call stacks of all leaks.
New output is clean now, so the issue may be closed.

==1713384== Memcheck, a memory error detector
==1713384== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1713384== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==1713384== Command: ./cpptest
==1713384== 
==1713384== 
==1713384== HEAP SUMMARY:
==1713384==     in use at exit: 0 bytes in 0 blocks
==1713384==   total heap usage: 101,001 allocs, 101,001 frees, 21,368,704 bytes allocated
==1713384== 
==1713384== All heap blocks were freed -- no leaks are possible
avaneev commented 10 months ago

Yes, I use a similar too - Dr.Memory.