这段代码中是否存在XS内存泄漏问题?

8

无法找到内存泄漏在这段代码中的发生位置。

基本上,我想为返回二维数组的C函数编写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()时,Perl进程的Commit大小都会增加。 但是我希望$arrayref变量每次都应该被垃圾回收,内存使用量不应该增加。
我希望在XS中释放了所有分配的内存。但仍然存在内存泄漏问题。 这个XS代码有什么问题导致内存泄漏?

你不需要使用newSVnv创建的标量进行任何解除分配。你应该自己创建并填充数组,而不是使用av_make复制所有这些SV。可以使用newAV+av_extend+av_fetch来创建和操作数组。 - ikegami
但是这段代码怎么办?/** 释放为临时SV数组分配的内存 **/ for(j = 0; j<count[i]; j++) { sv_free(SVtempArray[j]); }sv_free()调用不会释放使用newSVnv()创建的SV吗? - InnovWelt
永远不要调用 sv_free。使用 SvREFCNT_dec - ikegami
1个回答

7
好的,"创建一个模板数组,使用 av_make(),然后释放模板" 这种模式并不是很好 -- 你最好是用 newAV() 创建数组,av_extend() 将其扩展到正确的大小,然后为每个元素执行 av_store(newSVnv(...))。这样可以完全避免中间的 SVtempArray 分配。

然而,这不是你所询问的问题。我认为你的问题在于在 Safefree(SVArrays) 之前没有先 sv_free() 每个元素。由于 av_make() 复制了源数组的内容,据我所知,你正在泄漏由它创建的引用。

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

在你执行Safefree(SVArrays)之前,需要遍历SVArrays并对每个元素调用sv_free()


感谢指出代码中的问题。在一个地方使用了 sv_free()for(j = 0; j<count[i]; j++) { sv_free(SVtempArray[j]); })来释放SVs。但是在将最终数组推入堆栈后,这些SVs没有被 sv_free() - InnovWelt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接