2013-08-15 6 views
8

Невозможно найти место утечки памяти в этом коде.XS Ошибка утечки памяти в этом коде?

В основном я хочу написать оболочку XS для C-функции, которая возвращает двумерный массив.

С-функции:

int CW_returnArray(double** arrayDouble, int* count) 
{ 
    int number = 10; 
    int index, index1; 
    for(index = 0; index < number; index++) 
    { 
     for(index1 = 0; index1 < 10000; index1++) 
     { 
      arrayDouble[index][index1] = 12.51; 
     } 

     count[index] = 10000; 
    } 
    return number; 
} 

array -> output param to hold the two dimensional array 
count -> output param to hold the number of element in each 1D array 

XS обертка:

void 
returnArray() 
    PPCODE: 
    { 
    /** variable declaration **/ 
    double** array; 
    int i = 0, j=0, status; 
    int* count; 
    int totalArrays; 

    SV** SVArrays;  // to hold the references of 1D arrays 
    SV** SVtempArray; // temporary array to hold the elements of 1D array 

    /** allocate memory for C-type variables **/ 
    New(0, array, 10, double*); 

    for(i = 0; i<10;i++) 
    { 
     New(0, array[i], 10000, double); 
    } 

    New(0, count, 10, int); 

    /** call C function **/ 
    status = CW_returnArray(array, count); 

    /** check the status and retrieve the array to store it in stack **/ 
    if(status > 0) 
    { 
     totalArrays = status; 

     New(0, SVArrays, totalArrays, SV*); 
     for(i = 0; i<totalArrays; i++) 
     { 
      /** allocate memory for temporary SV array **/ 
      New(0, SVtempArray, count[i], SV*); 
      for(j = 0; j<count[i]; j++) 
      { 
       SVtempArray[j] = newSVnv(array[i][j]); 
      } 

      /** Make an array (AV) out of temporary SV array and store the reference in SVArrays **/ 
      SVArrays[i] = newRV_noinc((SV*) av_make(count[i], SVtempArray)); 

      /** free the memory allocated for temp SV array **/ 
      for(j = 0; j<count[i]; j++) 
      { 
       sv_free(SVtempArray[j]); 
      }    

      Safefree(SVtempArray); SVtempArray = NULL; 
     } 
    } 
    else 
    { 
     totalArrays = 0; 

    } 

    /** push the return values to stack **/ 
    EXTEND(SP, 2); 
    PUSHs(sv_2mortal(newSViv(status))); 
    PUSHs(sv_2mortal(newRV_noinc((SV*) av_make(totalArrays, SVArrays)))); 

    /** clean up allocated memory for SV "array of array" , if needed **/ 
    if(totalArrays > 0) 
    { 
     Safefree(SVArrays); SVArrays = NULL; 
    } 

    /** clean up allocated memory for C-type variables **/ 
    for(i = 0; i<10;i++) 
    { 
     Safefree(array[i]); 
    }  
    Safefree(array); array = NULL; 
    Safefree(count); count = NULL; 
} 

"массив массива" возвращается из XS.

тестирование в сценарии Perl:

for(1..100) 
{ 
    my ($status, $arrayref) = returnArray(); 
    undef $status; 
    $arrayref = []; 
    system('pause'); 
} 

Каждый раз, когда функция returnArray() называется, размер Commit процесса Perl растет. Но я бы ожидал, что переменная $arrayref должна каждый раз собираться мусором, а использование памяти не должно увеличиваться.

Надеюсь, я освобождаю всю выделенную память в XS. Но все же есть утечка памяти. Что не так с этим кодом XS для утечки памяти?

+0

Вы не освобождаете какой-либо из скаляров, созданных с помощью 'newSVnv'. Вместо копирования всех этих SV с помощью 'av_make' вам следует назначить создание массива самостоятельно. 'newAV' +' av_extend' + 'av_fetch' – ikegami

+0

Но как насчет этого кода? '/ ** освободить память, выделенную для временного массива SV **/ для (j = 0; j InnovWelt

+0

Никогда не называйте 'sv_free'. Используйте 'SvREFCNT_dec'. – ikegami

ответ

7

Ну, картина «создать массив-шаблон, сделать av_make(), а затем освободить шаблон» не очень хорошо - вы бы гораздо лучше, просто создавая свой массив с newAV(), av_extend() ИНГ его на нужный размер , а затем выполнив av_store(newSVnv(...)) для каждого элемента. Это позволяет полностью исключить промежуточные SVtempArray.

Однако, это не то, о чем вы просили. Я думаю, ваша проблема в том, что вы Safefree(SVArrays) без первого sv_free() ing каждый элемент. Поскольку av_make()дубликатами содержимое исходного массива, AFAICT вы протечки ссылку, созданную

SVArrays[i] = newRV_noinc((SV*) av_make(count[i], SVtempArray)); 

Вам нужно перебрать SVArrays и вызвать sv_free() каждого элемента перед вами Safefree(SVArrays).

+0

спасибо за указание на проблему с этим кодом. 'sv_free()' использовался в одном месте ('for (j = 0; j InnovWelt