2013-08-15 22 views
8

Impossibile trovare la causa della perdita di memoria in questo codice.Perdita di memoria XS in questo codice?

Fondamentalmente voglio scrivere un wrapper XS per una funzione C che restituisce un array bidimensionale.

C-funzione:

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 involucro:

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; 
} 

Un "array di matrice" viene restituito da XS.

test in script Perl:

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

Ogni volta che la funzione viene chiamata returnArray(), la dimensione Commit del processo Perl è in aumento. Ma mi aspetto che la variabile $arrayref debba essere raccolta ogni volta e l'utilizzo della memoria non dovrebbe aumentare.

Spero di liberare tutta la memoria allocata in XS. Ma c'è ancora una perdita di memoria. Cosa c'è di sbagliato in questo codice XS per perdita di memoria?

+0

Non si rilascia alcuno degli scalari creati utilizzando 'newSVnv'. Invece di copiare tutti questi SV usando 'av_make', dovresti assegnare crea un popolamento dell'array tu stesso. 'newAV' +' av_extend' + 'av_fetch' – ikegami

+0

Ma che dire di questo codice? '/ ** libera la memoria allocata per l'array SV temporaneo **/ per (j = 0; j InnovWelt

+0

Non chiamare mai 'sv_free'. Usa 'SvREFCNT_dec'. – ikegami

risposta

7

Ebbene, il modello di "creare un array modello, fare av_make(), quindi liberare il modello" non è molto buona - si sarebbe molto meglio semplicemente creando il tuo array con newAV(), av_extend() ing alla giusta dimensione e quindi facendo av_store(newSVnv(...)) per ciascun elemento. Ciò consente di evitare interamente le allocazioni intermedie SVtempArray.

Tuttavia, non è quello che hai chiesto. Penso che il tuo problema sia che tu sia Safefree(SVArrays) senza il primo sv_free() ogni elemento. Dal momento che av_make()duplicati i contenuti della matrice di origine, AFAICT si sta perdendo il riferimento creato da

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

Avrai bisogno di iterare SVArrays e chiamare sv_free() su ogni elemento prima di Safefree(SVArrays).

+0

grazie per aver segnalato il problema con questo codice. 'sv_free()' è stato usato in un posto ('for (j = 0; j InnovWelt