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


¥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 的引用不会阻止收集值。对象(对象、函数、外部)和符号类型的值正在成为 'weak' 引用,并且在未收集时仍然可以访问。任何大于 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 关联的对象将为返回的 napi_value 返回 NULL。尝试为其对象已收集的引用调用 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_reference_unref 之外还调用 napi_delete_reference 来避免。

¥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.

变更历史:

¥Change History:

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

    ¥Version 10 (NAPI_VERSION is defined as 10 or higher):

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

    ¥References can be created for all value types. The new supported value types do not support weak reference semantic and the values of these types are released when the reference count becomes 0 and cannot be accessed from the reference anymore.