2013-08-15 17 views
8

In diesem Code kann der Speicherleck nicht gefunden werden.XS Speicherleck in diesem Code?

Grundsätzlich möchte ich einen XS-Wrapper für eine C-Funktion schreiben, die ein zweidimensionales Array zurückgibt.

C-Funktion:

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

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

Ein "Array von Array" von XS zurückgegeben.

Tests in Perl-Skript:

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

Jedes Mal, wenn die Funktion returnArray() aufgerufen wird, wird die Commit Größe von Perl-Prozess zu erhöhen. Aber ich würde erwarten, dass die $arrayref Variable Müll jedes Mal gesammelt werden sollte und die Speicherbelegung sollte nicht erhöht werden.

Ich hoffe, ich befreie den gesamten zugewiesenen Speicher in XS. Aber immer noch gibt es ein Speicherleck. Was ist mit diesem XS-Code für Speicherverlust falsch?

+0

Sie können keine der Skalare, die mit 'newSVnv' erstellt wurden, deallozieren. Anstatt alle diese SVs mit 'av_make' zu ​​kopieren, sollten Sie create erstellen und das Array selbst auffüllen. 'newAV' +' av_extend' + 'av_fetch' – ikegami

+0

Aber was ist mit diesem Code? '/ ** gebe den Speicher frei, der für das temp SV-Array zugewiesen wurde **/ für (j = 0; j InnovWelt

+0

Niemals 'sv_free' aufrufen. Verwende 'SvREFCNT_dec'. – ikegami

Antwort

7

Nun, das Muster der „eine Vorlage Array erstellen, tun av_make(), dann die Vorlage frei“ ist nicht sehr gut - Sie Ihren Array viel besser sein würden mit newAV() durch einfaches Erstellen von av_extend() es auf die richtige Größe ing und dann av_store(newSVnv(...)) für jedes Element. Damit können Sie die Zwischen-SVtempArray Allokationen vollständig vermeiden.

Das ist jedoch nicht das, wonach Sie gefragt haben. Ich denke, Ihr Problem ist, dass Sie Safefree(SVArrays) ohne zuerst sv_free() jedes Element. Da av_make()Duplikate der Inhalt des Quell-Arrays, AFAICT Sie zum von

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

erstellt Referenz undicht werden Sie müssen über SVArrays iterieren und sv_free()Safefree(SVArrays), bevor Sie auf jedem Element aufrufen.

+0

Danke, dass Sie auf das Problem mit diesem Code hingewiesen haben. 'sv_free()' wurde an einer Stelle benutzt ('für (j = 0; j InnovWelt