#c #node.js #memory-leaks #v8 #node-addon-api
#c #node.js #утечки памяти #v8 #node-addon-api
Вопрос:
У меня есть надстройка узла c , которая использует библиотеку Nan. У меня есть функция, которая должна возвращать буфер. Самая простая ее версия выглядит следующим образом (код отредактирован в соответствии с комментариями):
NAN_METHOD(Test) {
char * retVal = (char*)malloc(100 * sizeof(char));
info.GetReturnValue().Set(Nan::NewBuffer(retVal, 100 *sizeof(char)).ToLocalChecked());
}
где объединение используется просто как простой способ переосмысления байтов. Согласно документации, Nan::NewBuffer принимает на себя право собственности на память, поэтому нет необходимости освобождать память вручную. Однако, когда я запускаю свой код узла, который использует эту функцию, моя память стремительно увеличивается, даже когда я заставляю сборщик мусора запускаться через global.gc();
Код узла, вызывающий ошибку, чрезвычайно прост:
const addon = require("addon");
for (let i = 0; i < 100000000; i ) {
if(i % (1000000) === 0){
console.log(i);
try {
global.gc();
} catch (e) {
console.log("error garbage collecting");
process.exit();
}
}
const buf = addon.Test();
}
Любая помощь будет оценена.
Комментарии:
1. (1) процедура gc вызывает
free
notdelete
( «… данные будут удалены с помощью вызова free() …» ); (2) наложение псевдонима на указатель через aunion
является неопределенным поведением; (3) даже если вызванная подпрограмма gcdelete
будет пытаться удалить указатель с псевдонимами, который является UB.2. @RichardCritten спасибо. Как мне достичь желаемого результата? будет ли работать переосмысленное приведение? Пункт об удалении и освобождении верен, но мне здесь не больно, поскольку уничтожать нечего.
3. Если вы не выполняете сопряжение
new/delete
, аmalloc/free
затем код находится в UB, и нет смысла пытаться рассуждать об этом.4. @RichardCritten итак, решением было бы использовать malloc вместо new . Я попробую это.
5. @RichardCritten та же утечка, после изменения на malloc (отредактировано в вопросе)
Ответ №1:
После долгих экспериментов и исследований я обнаружил это сообщение введите описание ссылки здесь, в котором в основном говорится, что обещание освободить память, которая передается в Nan::NewBuffer, — это просто ложь. Использование Nan::CopyBuffer вместо Nan::NewBuffer решает проблему за счет memcpy. Итак, по сути, ответ заключается в том, что Nan::NewBuffer сломан, и вы не должны его использовать. Вместо этого используйте Nan::CopyBuffer.
Ответ №2:
В НЕМ мы склонны называть ложь в документации ошибкой.
Этот вопрос был предметом Node.js проблема — https://github.com/nodejs/node/issues/40936
Ответ заключается в том, что освобождение базового буфера происходит в эквиваленте C обработчика JS SetImmediate
, и если ваш код полностью синхронен — что в вашем случае — буферы не будут освобождены до завершения программы.
Вы правильно обнаружили, что Nan::CopyBuffer
эта проблема не страдает.
Увы, это не может быть легко исправлено, поскольку Node.js не знает, как был выделен этот буфер, и не может вызвать его обратный вызов из контекста сборщика мусора.
Если вы используете Nan::NewBuffer
, я также предлагаю рассмотреть эту проблему: https://github.com/nodejs/node/issues/40926 в которой обсуждается еще одна тесно связанная с этим ловушка.
Комментарии:
1. ooof, в разработке программного обеспечения мы склонны избегать использования термина IT в качестве самоописания 😉