Надстройка узла Nan ::NewBuffer вызывает утечку памяти

#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 not delete ( «… данные будут удалены с помощью вызова free() …» ); (2) наложение псевдонима на указатель через a union является неопределенным поведением; (3) даже если вызванная подпрограмма gc delete будет пытаться удалить указатель с псевдонимами, который является 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 в качестве самоописания 😉