生命周期管理
【规则】 合理使用OH_JSVM_OpenHandleScope和OH_JSVM_CloseHandleScope管理JSVM_Value的生命周期,做到生命周期最小化,避免发生内存泄漏问题。
每个JSVM_Value属于特定的HandleScope,HandleScope通过OH_JSVM_OpenHandleScope和OH_JSVM_CloseHandleScope来建立和关闭,HandleScope关闭后,所属的JSVM_Value就会自动释放。
注意事项:
- JSVM_Value必须在HandleScope打开后才可创建(Node-API无该限制),否则会造成应用崩溃;
- JSVM_Value不能在其对应的HandleScope关闭后使用,如需持久化持有,需调用OH_JSVM_CreateReference转化为JSVM_Ref;
C++使用封装
class HandleScopeWrapper {
public:
HandleScopeWrapper(JSVM_Env env) : env(env) {
OH_JSVM_OpenHandleScope(env, &handleScope);
}
~HandleScopeWrapper() {
OH_JSVM_CloseHandleScope(env, handleScope);
}
HandleScopeWrapper(const HandleScopeWrapper&) = delete;
HandleScopeWrapper& operator=(const HandleScopeWrapper&) = delete;
HandleScopeWrapper(HandleScopeWrapper&&) = delete;
void* operator new(size_t) = delete;
void* operator new[](size_t) = delete;
protected:
JSVM_Env env;
JSVM_HandleScope handleScope;
};
示例:
// 在for循环中频繁调用JSVM接口创建js对象时,要加handle_scope及时释放不再使用的资源。
// 下面例子中,每次循环结束局部变量res的生命周期已结束,因此加scope及时释放其持有的js对象,防止内存泄漏
// 每次for循环结束后,触发HandleScopeWrapper的析构函数,释放scope持有的js对象
for (int i = 0; i < 100000; i++)
{
HandleScopeWrapper scope(env);
JSVM_Value res;
OH_JSVM_CreateObject(env, &res);
if (i == 1000) {
// break退出循环后会自动调用HandleScopeWrapper析构函数释放资源
break;
}
}
多引擎实例上下文敏感
【规则】 多引擎实例(VM)场景下,禁止通过JSVM-API跨引擎实例访问JS对象。
引擎实例是一个独立运行环境,JS对象创建访问等操作必须在同一个引擎实例中进行。若在不同引擎实例中操作同一个对象,可能会引发程序崩溃。引擎实例在接口中体现为JSVM_Env。
错误示例:
// 线程1执行,在env1创建string对象,值为"bar"、
OH_JSVM_CreateStringUtf8(env1, "value1", JSVM_AUTO_LENGTH , &string);
// 线程2执行,在env2创建object对象,并将上述的string对象设置到object对象中
JSVM_Status status = OH_JSVM_CreateObject(env2, &object);
if (status != JSVM_OK)
{
return;
}
status = OH_JSVM_SetNamedProperty(env2, object, "string1", string);
if (status != JSVM_OK)
{
return;
}
所有的JS对象都隶属于具体的某一JSVM_Env,不可将env1的对象,设置到env2中的对象中。在env2中一旦访问到env1的对象,程序可能会发生崩溃。
多线程共享引擎实例
【规则】多线程同时使用同一个引擎实例的场景下,需要加锁使用。保证一个引擎实例在同一时刻只能在一个线程执行。多线程同一时刻同时使用引擎实例可能造成应用崩溃。
注意事项:
- OH_JSVM_IsLocked的结果为当前线程是否持有