对生命周期比原生方法长的值的引用


【References to values with a lifespan longer than that of the native method】

在某些情况下,插件需要能够创建并引用生命周期超过单个本地方法调用的值。例如,要创建一个构造函数并在后续请求中使用该构造函数来创建实例,就必须能够在多个不同的实例创建请求中引用该构造函数对象。用前面章节中描述的 napi_value 返回的普通句柄是无法实现这一点的。普通句柄的生命周期由作用域管理,并且所有作用域必须在本地方法结束之前关闭。

【In some cases, an addon will need to be able to create and reference values with a lifespan longer than that of a single native method invocation. For example, to create a constructor and later use that constructor in a request to create instances, it must be possible to reference the constructor object across many different instance creation requests. This would not be possible with a normal handle returned as a napi_value as described in the earlier section. The lifespan of a normal handle is managed by scopes and all scopes must be closed before the end of a native method.】

Node-API 提供了用于创建值的持久引用的方法。目前,Node-API 只允许为有限类型的值创建引用,包括对象、外部、函数和符号。

【Node-API provides methods for creating persistent references to values. Currently Node-API only allows references to be created for a limited set of value types, including object, external, function, and symbol.】

每个引用都有一个关联的计数,其值为0或更高,这决定了引用是否会保持对应的值存活。计数为0的引用不会阻止值被回收。对象(对象、函数、外部对象)和符号类型的值将成为“弱”引用,并且在它们未被回收时仍然可以访问。任何大于0的计数都将阻止值被回收。

【Each reference has an associated count with a value of 0 or higher, which determines whether the reference will keep the corresponding value alive. References with a count of 0 do not prevent values from being collected. Values of object (object, function, external) and symbol types are becoming 'weak' references and can still be accessed while they are not collected. Any count greater than 0 will prevent the values from being collected.】

符号值有不同的类型。真正的弱引用行为只支持使用 napi_create_symbol 函数或 JavaScript Symbol() 构造函数创建的本地符号。使用 node_api_symbol_for 函数或 JavaScript Symbol.for() 函数创建的全局注册符号始终保持强引用,因为垃圾回收器不会回收它们。对于像 Symbol.iterator 这样的众所周知的符号也是如此,它们同样不会被垃圾回收器回收。

【Symbol values have different flavors. The true weak reference behavior is only supported by local symbols created with the napi_create_symbol function or the JavaScript Symbol() constructor calls. Globally registered symbols created with the node_api_symbol_for function or JavaScript Symbol.for() function calls remain always strong references because the garbage collector does not collect them. The same is true for well-known symbols such as Symbol.iterator. They are also never collected by the garbage collector.】

引用可以在创建时设置初始引用计数。然后可以通过 napi_reference_refnapi_reference_unref 修改计数。如果在引用的计数为 0 时对象被回收,随后对与该引用相关联的对象调用 napi_get_reference_value 将返回 NULL 作为返回的 napi_value。尝试对已被回收的对象的引用调用 napi_reference_ref 会导致错误。

【References can be created with an initial reference count. The count can then be modified through napi_reference_ref and napi_reference_unref. If an object is collected while the count for a reference is 0, all subsequent calls to get the object associated with the reference napi_get_reference_value will return NULL for the returned napi_value. An attempt to call napi_reference_ref for a reference whose object has been collected results in an error.】

一旦不再需要,必须删除引用。当引用被删除时,它将不再阻止相应的对象被回收。如果未删除持久引用,将导致“内存泄漏”,持久引用的本地内存和堆上的相应对象都会被永久保留。

【References must be deleted once they are no longer required by the addon. When a reference is deleted, it will no longer prevent the corresponding object from being collected. Failure to delete a persistent reference results in a 'memory leak' with both the native memory for the persistent reference and the corresponding object on the heap being retained forever.】

可以创建多个持久引用指向同一个对象,每个引用会根据其自身的计数决定是否保持对象的存活。对同一个对象的多个持久引用可能导致本地内存意外被保留。持久引用所对应的本地结构必须在被引用对象的终结器执行之前保持有效。如果为同一个对象创建新的持久引用,则该对象的终结器不会被执行,且早期持久引用所指向的本地内存不会被释放。可以通过在可能的情况下同时调用 napi_delete_referencenapi_reference_unref 来避免这种情况。

【There can be multiple persistent references created which refer to the same object, each of which will either keep the object live or not based on its individual count. Multiple persistent references to the same object can result in unexpectedly keeping alive native memory. The native structures for a persistent reference must be kept alive until finalizers for the referenced object are executed. If a new persistent reference is created for the same object, the finalizers for that object will not be run and the native memory pointed by the earlier persistent reference will not be freed. This can be avoided by calling napi_delete_reference in addition to napi_reference_unref when possible.】

更改历史:

  • 版本 10(NAPI_VERSION 定义为 10 或更高):

    可以为所有值类型创建引用。新支持的值类型不支持弱引用语义,并且当引用计数为0时,这些类型的值会被释放,无法再通过引用访问这些值。