Где утечка памяти в моем коде Perl XS?

У меня есть большая программа, написанная на C++ и выполняемая из Perl с использованием Inline::CPP. Код, кажется, использует много памяти, поэтому я предполагаю, что есть какая-то утечка. Я написал следующий код, который воспроизводит ту же проблему, но намного проще. Я обнаружил утечку, когда зациклил код 1 000 000 раз, чтобы проверить его производительность. Этот простой Perl-скрипт использует 828 МБ, а моя полная программа использует 1,3 ГБ.

Я пробовал много вещей, таких как использование SvREFCNT_dec, newRV_noinc, sv_free и sv_2mortal для различных переменных в коде, но мне не удалось снизить использование памяти.

Вот мой пример кода:

use Data::Dumper;

print Dumper test ();

use Inline 'CPP' => << 'CPP';
    #include <array>

    using namespace std;

    AV *array_to_av (const array<int,3> &v)
    {
        AV *array = newAV ();

        for (int i : v) {
            av_push (array, newSViv (i));
        }

        return array;
    }

    SV *test_leak ()
    {
        HV *hash = newHV ();

        AV *array1 = array_to_av ({1,2,3});
        AV *array2 = array_to_av ({1,2,3});
        AV *array3 = array_to_av ({1,2,3});

        SV *value1 = newRV_noinc ((SV *)(array1));
        SV *value2 = newRV_noinc ((SV *)(array2));
        SV *value3 = newRV_noinc ((SV *)(array3));

        hv_stores (hash, "Test1", value1);
        hv_stores (hash, "Test2", value2);
        hv_stores (hash, "Test3", value3);

        return newRV_noinc ((SV *)(hash));
    }

    SV *test ()
    {
        SV *hash;

        for (int i = 0; i < 1000000; i++) {
            hash = test_leak ();
        }

        return hash;
    }
CPP

sleep 10;

person Coffee'd Up Hacker    schedule 27.09.2020    source источник
comment
Я плохо разбираюсь в xs, но в аналогичном коде, который я написал, у меня есть sv_2mortal((SV*)flist); после AV* flist = newAV(); (затем заполняется массив flist и т. д.). Это для C, а не для C++.   -  person zdim    schedule 27.09.2020
comment
@zdim Размещение sv_2mortal ((SV*)array); после AV *array = newAV (); не изменило использование памяти, это только вызвало такие ошибки, как Попытка освободить нессылочный скаляр: SV 0x55748d5a6c68, интерпретатор Perl: 0x557458d6b2a0 в строке 54 testleak.pl. Код XS - это C, и вы можете написать стандартный C в C++, поэтому я не думаю, что это действительно имеет значение, использую ли я C++ или нет. Я также попытался удалить все функции C++ и вместо этого использовать Inline::C, но проблема осталась.   -  person Coffee'd Up Hacker    schedule 27.09.2020
comment
Хех... Я надеялся, что это поможет, так как я не вижу, что в показанном коде освобождает память. (Но теперь я также вижу, что неправильно понял, для чего нужен array_to_av()).   -  person zdim    schedule 27.09.2020


Ответы (1)


Вам нужно освободить хэши, которые не возвращаются Perl-скрипту в цикле for. Этот цикл:

for (int i = 0; i < 1000000; i++) {
    hash = test_leak ();
}

Должно быть что-то вроде:

for (int i = 0; i < 1000000; i++) {
    hash = test_leak ();
    SvREFCNT_dec(hash);  // Free the memory not returned to Perl
 }
 hash = test_leak();  // The final hashref is returned to Perl
person Håkon Hægland    schedule 27.09.2020