node-addon-api icon indicating copy to clipboard operation
node-addon-api copied to clipboard

Strange behavior

Open izirayd opened this issue 1 year ago • 0 comments

I'm new to nodejs, I took embedtest from nodejs and added napi to it, this way I got C++ Embed, after C++/nodejs/v8 is done I will get control back.

   v8::Local<v8::String>  source = v8::String::NewFromUtf8(isolate, s.c_str(), v8::NewStringType::kNormal).ToLocalChecked();
   v8::Local<v8::Script>  script = v8::Script::Compile(context, source).ToLocalChecked();
   v8::Local<v8::Value>   result = script->Run(context).ToLocalChecked();

The execution of the script itself will create an idle function registration on the js side:

import { player_t, StatusCode } from './player'

const player = new player_t();

player.registerIdle(() => {
    console.log(player.getLogin());
});

The player_t class is still on the js side, it talks to C++; So the registration looks like this:

    registerIdle(idleFunction: (player: player_t) => void) {
        this.player.registerIdle(idleFunction);
    }

I use NapiAddon

...
           InstanceMethod<&player_core_t::registerIdle>(
               "registerIdle",
                   static_cast<napi_property_attributes>(napi_writable |
                                                         napi_configurable)), 
 ...

Simple FunctionRef registration:

  Napi::Value registerIdle(const Napi::CallbackInfo& info) {

    Napi::Env env = info.Env();

    if (info.Length() != 1) {
      Napi::Error::New(env, "Invalid argument count")
          .ThrowAsJavaScriptException();
      return info.Env().Undefined();
    }

    if (!info[0].IsFunction()) {
      Napi::Error::New(env, "First argument not function")
          .ThrowAsJavaScriptException();
      return info.Env().Undefined();
    }

    IdleFunction = Napi::Persistent(info[0].As<Napi::Function>());

    return info.Env().Undefined();
  }

After script->Run I receive a stream and try to call idleFunc in a loop that will call a js function:

   for (size_t i = 0; i < 10000000; i++) {
      for (auto& players : player_core_t::listPlayers) {
       players->idleFunc();
     }
void idleFunc() {

   if (playerRef.IsEmpty()) 
        return;

    IdleFunction.Call({});

   }

The js side method is called and from the idle function lambda the other methods are working correctly. But I'm getting a memory leak. The memory is flying up in megabytes and I don’t understand the reason. It is logical that idle should constantly receive control from the thread.

What did I do wrong? Are there any workarounds?

I tested on nodejs18 and nodejs20. player_example.zip

izirayd avatar Mar 30 '24 11:03 izirayd