Decision Optimization

Decision Optimization

Delivers prescriptive analytics capabilities and decision intelligence to improve decision-making.

 View Only
  • 1.  Concert C++ API: Memory allocation of IloArray objects/possible memleakage?

    Posted Tue September 21, 2010 10:05 AM

    Originally posted by: DavidNLarsson


    Hi,

    I'm currently working on a problem where I'm implementing a Branch and Price algorithm, using ILOG CPLEX as the LP solver.
    Implementation is made in C++, using the ILOG Concert C++ API.

    Now, as I'm visiting nodes in my BNP tree, I naturally call some of my own functions (column generation etc) repeatedly.
    In these functions, I declare and use some CPLEX Concert objects temporarily, as might be done with "basic C++ objects/types"
    (e.g., for comparison, a float-array) in any "basic C++" function.

    My question(s) encompass the memory management of IloArray objects, in particular IloNumArray objects, the array class of
    Concert's basic floating-point class IloNum, and the need or no need to "delete" IloArray objects (using IloArray::end() method).

    Q1: Is an IloNumArray object allocated on the heap (i.e. dynamically), or can it be seen as "just a local floating-point-array"
    which - if declared locally in a function - would be deleted once we leave the function? (As the IloArray class rather
    resembles the vector class in "basic C++", I suspect the former option).

    Q2: If I fail to delete "local IloNumArray" objects in my repeatedly called functions (using IloArray::end()), does this lead
    to a risk of memory leakage? (I.e. rougue memory blocks left without associated pointers on the heap?)
    I've given an example below, of a situation where I'm led to ask myself the above questions. In the example function
    "someFunction(..)", the Concert objects of interest is an IloExpr and an IloNumArray object: tempExpr and tempNumArray, respectively.
    I know from Concert C++ examples that deletion of no-longer-used IloExtractables should always be done explicitely.

    (If I've understood correctly, the IloExpr object is a subclass of the IloExtractable base class, while the IloNumArray object is not.
    Further, an instance of IloExpr is passed by value, and not reference, so "deleting" the expression tempExpr in the end of the
    function (tempExpr.end();) wont affect any, say constraints, that has made use of the temporary expression in the function.
    However, should I also explicitely delete the IloNumArray tempNumArray, which only have local usage in the function?).

    // ------------------------------------------------------------------------------------
    // Risk of memory leaks for IloNumArray objects in functions called repeatedly?
    // ------------------------------------------------------------------------------------
     
    // libraries
    #include <ilcplex/ilocplex.h>
    ILOSTLBEGIN
     
    using namespace std;
     
    // function prototype(s)
    IloBool someFunction(IloCplex optSolver);
     
    int main (int argc, char **argv)
    {
            // create the optimization enviroment 
            IloEnv env;
     
            // no error catching for this simple example.. :)
     
            // create IloModel object associated with the optimization problem
            IloModel optModel(env);
     
    /* Add some objective function, constraints and variables to this model.. ... */
     
            // create associated cplex solver object for the model
            IloCplex optSolver(optModel);
     
            // now start some loop that will call someFunction() repeatedly (until som
            // termination criteria is met)
            for (;;) {
     
                    // now call someFunction which performs some operations
                    // on the model and returns "IloTrue" as long as some
                    // continue criteria is met.
                    if (! someFunction(optSolver) ) {
                            env.out() << "Termination criteria met: breaking. " << endl;
                            break;
                    }
            }
     
    /* print results.. ... */
            
            
            return 0;       
     
    } // END of main()
     
     
    // FUNCTION: someFunction(...)
    IloBool someFunction(IloCplex optSolver) {
     
            // extract optimization enviroment
            IloEnv env = optSolver.getEnv();
     
            // declare an IloNumArray object for local use in function
            IloNumArray tempNumArray(env);
     
            // declare an IloExpr object for local use in function
            IloExpr tempExpr(env);
     
            IloBool someReturnValue;
     
    /* Some operations on the model, using IloNumArray tempNumArray and IloExpr tempExpr.. ... Give value to someReturnValue.. */
     
     
            // Now, assume we've reached the end of whatever this function is
            // for, and that we are about to leave it.
     
            // We clear the memory allocated for temp. expression object tempExpr,
            // which is a subclass object of the base class IloExtractable.
            tempExpr.end();
     
            // How about the IloNumArray object tempNumArray? Can this be seen
            // just as a "local floating point array" that will be deleted once
            // we leave the active function? Or is the memory for the tempNumArray
            // allocated on the heap, e.g. only the _pointer_ tempNumArray is
            // deleted when we leave the function, leaving some rouge memory on
            // the heap: possible memory leakage situation?
            
            // tempNumArray.end(); <-- necessary?
     
            return someReturnValue;
     
    } // END of someFunction(...)
    

    #CPLEXOptimizers
    #DecisionOptimization


  • 2.  Re: Concert C++ API: Memory allocation of IloArray objects/possible memleakage?

    Posted Tue September 21, 2010 10:24 AM

    Originally posted by: SystemAdmin


    Answer to Q1: IloNumArray is just a "handle class". It is allocated on the stack but is merely just a wrapper for something that is allocated on the heap. The actual array of data will not be deleted by the destructor ~IloNumArray. You have to invoke IloNumArray::end() or you will leak memory.
    In this regard IloNumArray is quite different from std::vector. You may think of IloNumArray as being implemented like this (the real implementation is of course more involved):
    template<typename T> class IloNumArray {
       std::vector<T> *data;
    public:
      IloNumArray() : data(new std::vector<T>()) {}
      ~IloNumArray() { /* NOTHING! */ }
      void end() { delete data; }
      IloNumArray& operator=(IloNumArray const& from) { this.data = data; return *this; }
      // All operator[] forward lookups etc to data.
    };
    


    Answer to Q2: Yes, it does. You must call IloNumArray::end() when stop using it.

    In your example, I am pretty sure that you should end() the temporary IloNumArray instance or you will leak memory.
    #CPLEXOptimizers
    #DecisionOptimization


  • 3.  Re: Concert C++ API: Memory allocation of IloArray objects/possible memleakage?

    Posted Tue September 21, 2010 10:29 AM

    Originally posted by: DavidNLarsson


    Ah, I see, this sheds some light on the situation.

    Thank you for your quick answer Daniel!

    Regards,
    David.
    #CPLEXOptimizers
    #DecisionOptimization


  • 4.  Re: Concert C++ API: Memory allocation of IloArray objects/possible memleakage?

    Posted Wed September 22, 2010 09:26 AM

    Originally posted by: DavidNLarsson


    Further questions related to original post subject.
    #CPLEXOptimizers
    #DecisionOptimization


  • 5.  Re: Concert C++ API: Memory allocation of IloArray objects/possible memleakage?

    Posted Wed September 22, 2010 09:27 AM

    Originally posted by: DavidNLarsson


    Hi again,

    I have some additional questions w.r.t. the memory handling associated with methods
    used by IloArray.

    As the questions once again is related to the IloExtractable/IloArray::end() method
    and possible memory leaks, I post them here instead of starting a new thread.



    To summarize, given a 2-dimensional IloRangeArray object (typedef'd IloRangeArray2),
    I'm interested in how to properly remove a member of the IloRangeArray2 object (a member
    beeing an IloRangeArray object), without leaving some "un-pointed-to" memory on the heap,
    alternatively leaving a wild pointer in the IloRangeArray2 object (with it's previously
    related memory gone/deleted).

    I continue on the subject stated in my first post, and give an example below where's I'm
    led to investigate the matter. In this case, we focus on a Branch and Bound algorithm
    (no node-dynamic pricing).

    My questions are posted as Q1.1, Q2.1, Q3.1 and Q3.2 in the comments of the code below,
    following my 3 proposals/alternatives of deletion procedure.

    Thanks in advance,
    David.

    // ------------------------------------------------------------------------------------
    // Risk of memory leaks with improper removal of IloRangeArray/IloRange objects?
    // ------------------------------------------------------------------------------------
     
    // libraries
    #include <ilcplex/ilocplex.h>
    ILOSTLBEGIN
     
    using namespace std;
     
    // constants
    #define TOP_OF_LIST 0
     
    // function prototype(s)
    static void initializeProblemList(IloRangeArray2 problemList)
     
    // typedef array object for 2-dim IloRangeArray.
    typedef IloArray<IloRangeArray> IloRangeArray2;
     
    int main (int argc, char **argv)
    {
            // create the optimization enviroment 
            IloEnv env;
     
            // no error catching for this simple example.. :)
     
    /* Add IloModel objects for the restricted master program (RMP), and for some pricing subproblems, aswell as associated objective functions, constraints, variables etc. Create associated cplex solver objects... ... */
     
            // In this example, we focus only on a branch and bound algorithm.
            // Assume we have completed a column generation w.r.t. the original
            // RMP, and that we now want to perform some branching on the RMP LP
            // optimal solution to obtain an integer solution. (Best possible given
            // the generated columns)
     
            // We choose to represent out bnb node tree/active problems list using
            // a 2-d IloRangeArray, where each problem in the tree is represented 
            // as a number of cuts w.r.t. to the original RMP.
            IloRangeArray2 problemList(env);
     
            // initialize problem list with original RMP (no cuts)
            initializeProblemList(problemList);
     
    /* Lets assume we run a simple branch and bound algorithm which initially increases the size of the problem list. Before proceeding, I quickly explain how new/branched problems are entered into the problem list: all expressions and associated upper/lower bounds are extracted from the parent node (beeing branched on), and COPIED (as IloExpr is passed by value) to the two child nodes, thereafter adding the new cuts for each new problem. The key point here is that each problem in the problemlist is represented - memorywise - as an _independent_ IloRangeArray (i.e. no IloRange member objects shared with other problems/IloRangeArrays). Now, at some time during the BNB process, consider the problem with index i in the list: problemList[i] As described above, problemList[i] is an IloRangeArray. Let's assume it contains 4 IloRange members, that is, 4 cuts w.r.t. the original model. Further, let's assume we solve this (LP) problem i (i.e. original RMP+cuts described by problemList[i] IloRangeArray), and are able to prune it by some criteria (bound/optimality etc). So before proceeding with another problem from the list, we need to REMOVE the problem/node just processed from the problem list. Here is the essence of my question, how to properly remove an independent IloRangeArray object from my 2-d IloRangeArray problem list. My goal is to remove the problem (IloRangeArray) from the list, (while leaving no "gaps" in the IloRangeArray2 problemList), and guarantee that no rougue memory is left on the heap. I post some possible alternatives below, followed by my understanding of what each alternative do, w.r.t. memoryhandling and structure of the problemList. Alternative #1: problemList.remove(i); Simply removes the i:th element of the IloRangeArray2 problemList. Pros: the IloArray::remove() method removes the given member and make sure no gap is left in the array at hand (e.g. problemList decreases in size by one member, without leaving any "index gaps"). Cons: As this member should just be a pointer to an associated IloRangeArray, Q1.1: I'm pretty sure this procedure just throws away the pointer and leaves the memory pointed to intact? E.g., not a method I would want to use? (or is the IloArray::remove() method more thorough?) Alternative #2: problemList[i].end(); I use the IloRangeArray::end() method to "free all the resources used by the invoking object problemList[i]", which is okay as any problem removal (from list) is performed after all associated cuts have been explicitely removed from the master model. Q2.1: Will this guarantee that I also remove all 4 IloRange objects contained in the IloRangeArray from the memory, e.g., same effect as if I would "end()" these 4 IloRange objects explicitely? (i.e. "for j=0->3: problemList[i][j].end() -> problemList[i].end()") Q2.2: As the IloRangeArray::end() method as a final step deletes the invoking IloRangeArray object (e.g. problemList[i]), will this member (e.g. pointer) of the IloRangeArray2 problemList be "cut away" from the list in the same way as when using the IloArray::remove() method, described in Alternative #1? Alternative #3: problemList[i].end(); problemList.remove(i); Q3.1: (In essence same question as Q2.2) If "problemList[i].end()" only deletes the IloRangeArray object pointed to by problemList[i], must I remove the i:th pointer explicitely to make sure not to leave a wild pointer in the problemList (and to ensure the problem list is decreased)? My guess is that Alternative #3 would work, but as I'm not really sure how "thorough" the IloRangeArray::end() method is, I'm a bit unsure. */
            
            
            return 0;       
     
    } // END of main()
     
     
    // ---------------------------------------------------------------------------------------------------------- //
    // Function: initializeProblemList(...)
    //
    // Purpose: Initializes problem list by adding the original rmp problem to the list, as
    // a redundant constraint/cut that does not effect the original problem.
    // ---------------------------------------------------------------------------------------------------------- //
     
    static void initializeProblemList(IloRangeArray2 problemList)  {
     
            // extract optimization enviroment
            IloEnv env = problemList.getEnv();
     
            // allocate space in the problem list for the initial problem/node.
            problemList.add(IloRangeArray(env));
     
            // add the redundant "zero constraint" (empty)
            problemList[TOP_OF_LIST].add(-IloInfinity <= IloExpr(env) <= IloInfinity);
     
    }
    

    #CPLEXOptimizers
    #DecisionOptimization


  • 6.  Re: Concert C++ API: Memory allocation of IloArray objects/possible memleakage?

    Posted Wed September 22, 2010 10:17 AM

    Originally posted by: SystemAdmin


    I think the following should work and should not cause any leaks (though I did not test it, nor did I double-check with the source code):
    problemList[i].endElements();
    problemList[i].end();
    probemList.remove(i);
    

    However, before you continue in this direction: Did you think about the overhead that IloRangeArray::remove() will produce (moving all elements after i one slot to the front). Maybe you are better off with a linked data structure here?
    #CPLEXOptimizers
    #DecisionOptimization


  • 7.  Re: Concert C++ API: Memory allocation of IloArray objects/possible memleakage?

    Posted Wed September 22, 2010 11:00 AM

    Originally posted by: DavidNLarsson


    Thank you Daniel, it works in my program and seemingly removes any logical error that might lead to memory leakage.

    And thanks for the notion on using a linked data structure, I shall look into that in a later phase. Right now my main focus is examinating different branching rules, and the only implementation issue I'm trying to be thorough with is avoiding memory leaks.

    Have a nice day!

    Regards,
    David.
    #CPLEXOptimizers
    #DecisionOptimization


  • 8.  Re: Concert C++ API: Memory allocation of IloArray objects/possible memleakage?

    Posted Wed September 22, 2010 11:09 AM

    Originally posted by: SystemAdmin


    Just for the sake of correctness: I think this was not mentioned so far in this thread:
    You would not really cause memory leaks by the stuff you described in your previous postings. The IloEnv instance keeps a pointer to everything that it ever allocated and once you invoke env.end() all memory will be released.
    However, in your case you will pile up a lot of memory that is unused and should be released earlier. So technically you are not leaking memory here but you are wasting memory (which is almost as bad).
    #CPLEXOptimizers
    #DecisionOptimization