|
| 1 | +# Object lifetime management |
| 2 | + |
| 3 | +A handle may be created when any new node-addon-api Value and |
| 4 | +its subclasses is created or returned. |
| 5 | + |
| 6 | +As the methods and classes within the node-addon-api are used, |
| 7 | +handles to objects in the heap for the underlying |
| 8 | +VM may be created. A handle may be created when any new |
| 9 | +node-addon-api Value or one of its subclasses is created or returned. |
| 10 | +These handles must hold the objects 'live' until they are no |
| 11 | +longer required by the native code, otherwise the objects could be |
| 12 | +collected by the garbage collector before the native code was |
| 13 | +finished using them. |
| 14 | + |
| 15 | +As handles are created they are associated with a |
| 16 | +'scope'. The lifespan for the default scope is tied to the lifespan |
| 17 | +of the native method call. The result is that, by default, handles |
| 18 | +remain valid and the objects associated with these handles will be |
| 19 | +held live for the lifespan of the native method call. |
| 20 | + |
| 21 | +In many cases, however, it is necessary that the handles remain valid for |
| 22 | +either a shorter or longer lifespan than that of the native method. |
| 23 | +The sections which follow describe the node-addon-api classes and |
| 24 | +methods that than can be used to change the handle lifespan from |
| 25 | +the default. |
| 26 | + |
| 27 | +## Making handle lifespan shorter than that of the native method |
| 28 | + |
| 29 | +It is often necessary to make the lifespan of handles shorter than |
| 30 | +the lifespan of a native method. For example, consider a native method |
| 31 | +that has a loop which creates a number of values and does something |
| 32 | +with each of the values, one at a time: |
| 33 | + |
| 34 | +```C++ |
| 35 | +for (int i = 0; i < LOOP_MAX; i++) { |
| 36 | + std::string name = std::string("inner-scope") + std::to_string(i); |
| 37 | + Value newValue = String::New(info.Env(), name.c_str()); |
| 38 | + // do something with neValue |
| 39 | +}; |
| 40 | +``` |
| 41 | + |
| 42 | +This would result in a large number of handles being created, consuming |
| 43 | +substantial resources. In addition, even though the native code could only |
| 44 | +use the most recently created value, all of the previously created |
| 45 | +values would also be kept alive since they all share the same scope. |
| 46 | + |
| 47 | +To handle this case, node-addon-api provides the ability to establish |
| 48 | +a new 'scope' to which newly created handles will be associated. Once those |
| 49 | +handles are no longer required, the scope can be deleted and any handles |
| 50 | +associated with the scope are invalidated. The `HandleScope` |
| 51 | +and `EscapableHandleScope` classes are provided by node-addon-api for |
| 52 | +creating additional scopes. |
| 53 | + |
| 54 | +node-addon-api only supports a single nested hierarchy of scopes. There is |
| 55 | +only one active scope at any time, and all new handles will be associated |
| 56 | +with that scope while it is active. Scopes must be deleted in the reverse |
| 57 | +order from which they are opened. In addition, all scopes created within |
| 58 | +a native method must be deleted before returning from that method. Since |
| 59 | +HandleScopes are typically stack allocated the compiler will take care of |
| 60 | +deletion, however, care must be taken to create the scope in the right |
| 61 | +place such that you achieve the desired lifetime. |
| 62 | + |
| 63 | +Taking the earlier example, creating a HandleScope in the innner loop |
| 64 | +would ensure that at most a single new value is held alive throughout the |
| 65 | +execution of the loop: |
| 66 | + |
| 67 | +```C |
| 68 | +for (int i = 0; i < LOOP_MAX; i++) { |
| 69 | + HandleScope scope(info.Env()); |
| 70 | + std::string name = std::string("inner-scope") + std::to_string(i); |
| 71 | + Value newValue = String::New(info.Env(), name.c_str()); |
| 72 | + // do something with neValue |
| 73 | +}; |
| 74 | +``` |
| 75 | + |
| 76 | +When nesting scopes, there are cases where a handle from an |
| 77 | +inner scope needs to live beyond the lifespan of that scope. node-addon-api |
| 78 | +provides the `EscapableHandleScope` with the Escape method |
| 79 | +in order to support this case. An escapable scope |
| 80 | +allows one object to be 'promoted' so that it 'escapes' the |
| 81 | +current scope and the lifespan of the handle changes from the current |
| 82 | +scope to that of the outer scope. The Escape method can only be called |
| 83 | +once for a given EscapableHandleScope. |
0 commit comments