mercredi 5 juillet 2017

C++ Memory Leak in Swig Python Module

I have created a python module that wraps a C++ program using SWIG. It works just fine, but it has a pretty serious memory leak issue that I've pinned down to a few specific lines. I have very little experience with C++, and I have questions as to whether delete[] can be used on an object created with new in a different function or method.

The program was written in 2007, so excuse the lack of useful c++11 tricks.


The methods in question:

map<long long, double> *Matrix::calcDistribWithMapMinMax (long long min, long long max) { 

  map<long long, double> *nbocc = new map<long long, double> [length+1]; 
  // Memory leak is a result of nbocc.

  // ...computations here

  return nbocc;

nbocc is then used and deleted in the follow method:

/**
* Computes the pvalue associated with the threshold score requestedScore.
 */
void Matrix::lookForPvalue (long long requestedScore, long long min, long long max, double *pmin, double *pmax) {

  map<long long, double> *nbocc = calcDistribWithMapMinMax(min,max); 
  map<long long, double>::iterator iter;

  // computes p values and stores them in nbocc[length] 
  double sum = nbocc[length][max+1];
  long long s = max + 1;
  map<long long, double>::reverse_iterator riter = nbocc[length-1].rbegin();
  while (riter != nbocc[length-1].rend()) {
    sum += riter->second;
    if (riter->first >= requestedScore) s = riter->first;
    nbocc[length][riter->first] = sum;
    riter++;      
  }

  iter = nbocc[length].find(s);
  while (iter != nbocc[length].begin() && iter->first >= s - errorMax) {
    iter--;      
  }

  *pmax = nbocc[length][s];
  *pmin = iter->second;

  delete[] nbocc;

}

However, the memory used by nbocc is not released. Is this use valid?

I have tried using gc.collect() and I am using the multiprocessing module as recommended in this question to call these functions from my python program. I've also tried deleting the Matrix object (despite it being scoped properly) from within python to no avail as well.

Here is the python function I use to call the above C++ method:

def score2pval(matrix, req_score):
    """
    Determine the p-value for a given score for a specific motif PWM.

    Args:
        matrix (pytfmpval Matrix): Matrix in pwm format.
        req_score (float): Requested score for which to determine the p-value.

    Returns:
        ppv (float): The calculated p-value corresponding to the score.
    """

    granularity = 0.1
    max_granularity = 1e-10
    decrgr = 10  # Factor to increase granularity by after each iteration.

    pv = tfm.doublep()
    ppv = tfm.doublep()

    while granularity > max_granularity:
        matrix.computesIntegerMatrix(granularity)
        max_s = int(req_score * matrix.granularity + matrix.offset + matrix.errorMax + 1)
        min_s = int(req_score * matrix.granularity + matrix.offset - matrix.errorMax - 1)
        score = int(req_score * matrix.granularity + matrix.offset)

        matrix.lookForPvalue(score, min_s, max_s, ppv, pv)
        # Leak occurs here.

        if ppv.value() == pv.value():
            return ppv.value()

        granularity = granularity / decrgr

    print("Max granularity exceeded. Returning closest approximation.")
    return ppv.value()

I can post additional code if it'd be helpful, I just figured I would keep it brief for now.

Aucun commentaire:

Enregistrer un commentaire