# 使用JSVM-API感知JSVM引擎生命周期管理

#### 简介

JSVM-API提供了注册回调函数的能力，用于监测JavaScript虚拟机的内存GC。开发者可以在垃圾回收前后添加自定义逻辑，从而在垃圾回收时执行优化、调试或性能监控操作。

#### 基本概念

在JavaScript中，内存的垃圾回收是自动进行的，用户并不直接感知JavaScript虚拟机的GC行为。每次GC执行之前，JS引擎会先进入一个"Prologue"阶段。每次GC执行之后，JS引擎会进入一个"Epilogue"阶段。"Prologue"阶段是GC的初始阶段，主要目标是做一些准备工作，以确保垃圾回收能够顺利进行。"Epilogue"阶段则是垃圾回收的最终清理和整理，确保内存恢复到一个正常的状态，并为下一次分配做好准备。在这两个阶段，JS引擎会分别调用用户提前注册的函数。用户可以在"Prologue"阶段所执行的注册函数中暂停某些任务、记录内存使用情况、执行性能调优等。在"Epilogue"阶段所执行的注册函数中，也可以去记录GC后的内存状态、启动后续的任务等等。

JSVM-API提供了OH\_JSVM\_AddHandlerForGC接口，可以在VM中注册回调函数。通过传入JSVM\_CB\_TRIGGER\_BEFORE\_GC来控制回调函数在"Prologue"阶段执行；通过传入JSVM\_CB\_TRIGGER\_AFTER\_GC来控制回调函数在"Epilogue"阶段执行。通过OH\_JSVM\_RemoveHandlerForGC，可以从VM中移除注册过的回调函数。

#### 接口说明

| 接口 | 功能说明 |
| --- | --- |
| OH_JSVM_AddHandlerForGC | 用于向VM中注册回调函数 |
| OH_JSVM_RemoveHandlerForGC | 用于从VM中移除注册过的回调函数 |

#### 使用示例

JSVM-API接口开发流程参考使用JSVM-API实现JS与C/C++语言交互开发流程，本文仅对接口对应C++相关代码进行展示。

#### OH\_JSVM\_AddHandlerForGC & OH\_JSVM\_RemoveHandlerForGC

可以多次调用OH\_JSVM\_AddHandlerForGC向VM注册回调函数，所有注册的回调函数都会生效。注册时，以回调函数指针和native-data作为键。如果多次注册存在相同的键，则视为无效注册，并返回JSVM\_INVALID\_ARG错误码。在相同触发条件下，回调函数的回调顺序与注册顺序不严格一致。

通过OH\_JSVM\_RemoveHandlerForGC可以从VM中移除注册过的回调函数。重复移除具有相同key的回调函数，则会判定为无效移除，并返回JSVM\_INVALID\_ARG错误码。

**cpp部分代码**

```
// hello.cpp
#include <iostream>

static bool before_flag1 = false;
static bool before_flag2 = false;
static bool after_flag1 = false;
static bool after_flag2 = false;

void OnBeforeGC(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data)
{
    OH_LOG_INFO(LOG_APP, "== before GC ==");
    OH_LOG_INFO(LOG_APP, "gc type: %{public}d", gcType);
    OH_LOG_INFO(LOG_APP, "gc flag: %{public}d", flags);
    before_flag1 = true;
}

void OnBeforeGC2(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data)
{
    OH_LOG_INFO(LOG_APP, "== before GC2 ==");
    OH_LOG_INFO(LOG_APP, "gc type: %{public}d", gcType);
    OH_LOG_INFO(LOG_APP, "gc flag: %{public}d", flags);
    OH_LOG_INFO(LOG_APP, "data: %{public}d", *(int*)data);
    if (*(int*)data == 2024) {
        before_flag2 = true;
    }
}

void OnAfterGC(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data)
{
    after_flag1 = true;
}

void OnAfterGC2(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data)
{
    after_flag2 = true;
}

void OnAfterGC3(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data)
{
    after_flag2 = true;
}

static JSVM_Value TriggerGC(JSVM_Env env, JSVM_CallbackInfo info)
{
    bool remove_repeated = false;
    bool remove_notAdded = false;
    bool add_repeated = false;
    before_flag1 = false;
    before_flag2 = false;
    after_flag1 = false;
    after_flag2 = false;
    JSVM_VM vm;
    OH_JSVM_GetVM(env, &vm);
    // 设置两个回调函数，在GC执行之前触发回调
    int data = 2024;
    JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_BEFORE_GC, OnBeforeGC, JSVM_GC_TYPE_ALL, NULL));
    JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_BEFORE_GC, OnBeforeGC2, JSVM_GC_TYPE_ALL, (void*)(&data)));
    // 设置两个回调函数，在GC执行之后触发回调
    JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC, JSVM_GC_TYPE_ALL, NULL));
    JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, JSVM_GC_TYPE_ALL, NULL));
    // (OnAfterGC2, NULL)的组合已经注册过了，重复注册为无效行为
    if (OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, JSVM_GC_TYPE_ALL, NULL) == JSVM_INVALID_ARG) {
        add_repeated = true;
    }
    // 移除OnAfter2回调函数
    JSVM_CALL(OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, NULL));
    // 重复移除OnAfter2属于无效用法
    if (OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, NULL) == JSVM_INVALID_ARG) {
        remove_repeated = true;
    }
    // 移除从未设置过的函数属于无效用法
    if (OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC3, NULL) == JSVM_INVALID_ARG) {
        remove_notAdded = true;
    }
    // 通知引擎当前存在比较大的内存压力，能大概率触发JS引擎的GC流程。
    JSVM_CALL(OH_JSVM_MemoryPressureNotification(env, JSVM_MEMORY_PRESSURE_LEVEL_CRITICAL));
    if ((before_flag1) &&
        (before_flag2) &&
        (after_flag1) &&
        (!after_flag2) &&
        (remove_repeated) &&
        (remove_notAdded) &&
        (add_repeated)) {
        OH_LOG_INFO(LOG_APP, "JSVM Trigger GC: success");
    } else {
        OH_LOG_ERROR(LOG_APP, "JSVM Trigger GC: failed");
    }
    JSVM_Value checked;
    OH_JSVM_GetBoolean(env, true, &checked);
    return checked;
}

static JSVM_CallbackStruct param[] = {
    {.data = nullptr, .callback = TriggerGC},
};
static JSVM_CallbackStruct *method = param;

static JSVM_PropertyDescriptor descriptor[] = {
    {"triggerGC", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT},
};
```

**样例测试JS**

```
const char *srcCallNative = R"JS(triggerGC();)JS";
```

**执行结果**

在LOG中输出下面结果：

```
== before GC ==
gc type: 4
gc flag: 4
== before GC2 ==
gc type: 4
gc flag: 4
data: 2024
JSVM Trigger GC: success
```