Встроенный Perl FREETMPS неправильно очищает массив хеш-ссылок
У меня есть проект с несколькими макросами, которые помогают мне писать функции Perl и в основном «преобразовывать» структуры C в хэши Perl. Некоторые из этих хэшей вложены друг в друга, но я перейду к сути.
Использование памяти моей программой резко возрастает с течением времени, это интерфейс для социальных сетей, написанный на C и Embedded Perl (странный выбор языка, но это неважно). Я на 100% уверен, что нашел основную причину кода, так как его удаление и другие вещи приводят к его исчезновению, и я также профилировал его, и каждая проблема указывает на мой массив хэшей.
if (notifs && notifs_len)
{
// Leak occurs here
mXPUSHs(newRV_noinc((SV*)perlify_notifications(notifs, notifs_len)));
}
else ARG_UNDEFINED();
// Run function
PERL_STACK_SCALAR_CALL("base_page");
char* dup = PERL_GET_STACK_EXIT;
Где PERL_GET_STACK_EXIT — это макрос, который соответствует
#define PERL_GET_STACK_EXIT savesharedsvpv(POPs); \
PUTBACK; \
FREETMPS; \
LEAVE; \
perl_unlock()
// Macros for storing data
#define hvstores_str(hv, key, val) if (val) { hv_stores((hv), key, newSVpv((val), 0)); }
#define hvstores_int(hv, key, val) hv_stores((hv), key, newSViv((val)))
#define hvstores_ref(hv, key, val) if (val) { hv_stores((hv), key, newRV_noinc((SV*)(val))); }
// Calls one of the `perlify_X` functions for each element in an array
// Note: I was not using av_push before, I only temporarily switched thinking that was the issue or if I was misreading the docs
// EX: PERLIFY_MULTI(notification, notifications, notification_t
#define PERLIFY_MULTI(type, types, mstype) AV* perlify_##types(const struct mstype* const types, size_t len) { \
if (!(types && len)) return NULL; \
AV* av = newAV(); \
for (size_t i = 0; i < len; ++i) \
av_push(av, newRV_noinc((SV*)perlify_##type(types + i))); \
return av; \
}
Сделав шаг вперед, вот хеш-функции. Такой как
// Converts it into a perl struct
HV* perlify_notification(const struct mstdnt_notification* const notif)
{
if (!notif) return NULL;
HV* notif_hv = newHV();
// Profiler doesn't show much data leaking for these 4, so I am uncertain
hvstores_str(notif_hv, "id", notif->id);
hvstores_int(notif_hv, "created_at", notif->created_at);
hvstores_str(notif_hv, "emoji", notif->emoji);
hvstores_str(notif_hv, "type", mstdnt_notification_t_to_str(notif->type));
// The functions below seem to leak the most (and they store a bunch of data), if I comment them out, most of the
// memleak is gone (because these output a lot of data). The functions
// being called look equivalent to this one, so it's no secret.
hvstores_ref(notif_hv, "account", perlify_account(notif->account));
hvstores_ref(notif_hv, "pleroma", perlify_notification_pleroma(notif->pleroma));
hvstores_ref(notif_hv, "status", perlify_status(notif->status));
return notif_hv;
}
Я попытался скомпилировать весь Perl из исходного кода, так как я на Gentoo, чтобы отладить эту проблему и изучить внутренности FREETMPS, и попытался увидеть, что происходит. Я пытался сбросить все ссылки, которые мог, но каждый объект имел REFCNT, равный 1. Не повезло
Когда я запускал это с помощью массива, просматривая его с помощью Top, я просто наблюдал, как медленно увеличивается память. Я проверил свою удачу с помощью проб и ошибок: он начинается примерно с 9 МБ, затем медленно увеличивается до 15–25 МБ использования памяти, пока я продолжаю вызывать эти функции снова и снова. Конечно, если я закомментирую FREETMPS или просто запущу функции без каких-либо других действий, использование памяти увеличится с той же скоростью, что и раньше. Я все еще уверен, что это основная проблема.
Я действительно в растерянности, я делаю что-то не так с тем, как я «перлифифицирую» свои структуры C?