1# 使用JSVM-API感知JSVM引擎生命周期管理 2<!--Kit: NDK Development--> 3<!--Subsystem: arkcompiler--> 4<!--Owner: @yuanxiaogou; @string_sz--> 5<!--Designer: @knightaoko--> 6<!--Tester: @test_lzz--> 7<!--Adviser: @fang-jinxu--> 8 9## 简介 10 11JSVM-API提供了注册回调函数的能力,用于监测JavaScript虚拟机的内存GC。开发者可以在垃圾回收前后添加自定义逻辑,从而在垃圾回收时执行优化、调试或性能监控操作。 12 13## 基本概念 14 15在JavaScript中,内存的垃圾回收是自动进行的,用户并不直接感知JavaScript虚拟机的GC行为。每次GC执行之前,JS引擎会先进入一个"Prologue"阶段。每次GC执行之后,JS引擎会进入一个"Epilogue"阶段。"Prologue"阶段是GC的初始阶段,主要目标是做一些准备工作,以确保垃圾回收能够顺利进行。"Epilogue"阶段则是垃圾回收的最终清理和整理,确保内存恢复到一个正常的状态,并为下一次分配做好准备。在这两个阶段,JS引擎会分别调用用户提前注册的函数。用户可以在"Prologue"阶段所执行的注册函数中暂停某些任务、记录内存使用情况、执行性能调优等。在"Epilogue"阶段所执行的注册函数中,也可以去记录GC后的内存状态、启动后续的任务等等。 16 17JSVM-API提供了OH_JSVM_AddHandlerForGC接口,可以在VM中注册回调函数。通过传入JSVM_CB_TRIGGER_BEFORE_GC来控制回调函数在"Prologue"阶段执行;通过传入JSVM_CB_TRIGGER_AFTER_GC来控制回调函数在"Epilogue"阶段执行。通过OH_JSVM_RemoveHandlerForGC,可以从VM中移除注册过的回调函数。 18 19## 接口说明 20 21| 接口 | 功能说明 | 22|----------------------------|-------------------------------------| 23| OH_JSVM_AddHandlerForGC | 用于向VM中注册回调函数| 24| OH_JSVM_RemoveHandlerForGC | 用于从VM中移除注册过的回调函数| 25 26## 使用示例 27 28JSVM-API接口开发流程参考[使用JSVM-API实现JS与C/C++语言交互开发流程](use-jsvm-process.md),本文仅对接口对应C++相关代码进行展示。 29 30### OH_JSVM_AddHandlerForGC & OH_JSVM_RemoveHandlerForGC 31 32可以多次调用OH_JSVM_AddHandlerForGC向VM注册回调函数,所有注册的回调函数都会生效。注册时,以回调函数指针和native-data作为键。如果多次注册存在相同的键,则视为无效注册,并返回JSVM_INVALID_ARG错误码。在相同触发条件下,回调函数的回调顺序与注册顺序不严格一致。 33通过OH_JSVM_RemoveHandlerForGC可以从VM中移除注册过的回调函数。重复移除具有相同key的回调函数,则会判定为无效移除,并返回JSVM_INVALID_ARG错误码。 34 35**cpp部分代码** 36 37```cpp 38// hello.cpp 39#include <iostream> 40 41static bool before_flag1 = false; 42static bool before_flag2 = false; 43static bool after_flag1 = false; 44static bool after_flag2 = false; 45 46void OnBeforeGC(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 47{ 48 OH_LOG_INFO(LOG_APP, "== before GC =="); 49 OH_LOG_INFO(LOG_APP, "gc type: %{public}d", gcType); 50 OH_LOG_INFO(LOG_APP, "gc flag: %{public}d", flags); 51 before_flag1 = true; 52} 53 54void OnBeforeGC2(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 55{ 56 OH_LOG_INFO(LOG_APP, "== before GC2 =="); 57 OH_LOG_INFO(LOG_APP, "gc type: %{public}d", gcType); 58 OH_LOG_INFO(LOG_APP, "gc flag: %{public}d", flags); 59 OH_LOG_INFO(LOG_APP, "data: %{public}d", *(int*)data); 60 if (*(int*)data == 2024) { 61 before_flag2 = true; 62 } 63} 64 65void OnAfterGC(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 66{ 67 after_flag1 = true; 68} 69 70void OnAfterGC2(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 71{ 72 after_flag2 = true; 73} 74 75void OnAfterGC3(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 76{ 77 after_flag2 = true; 78} 79 80static JSVM_Value TriggerGC(JSVM_Env env, JSVM_CallbackInfo info) 81{ 82 bool remove_repeated = false; 83 bool remove_notAdded = false; 84 bool add_repeated = false; 85 before_flag1 = false; 86 before_flag2 = false; 87 after_flag1 = false; 88 after_flag2 = false; 89 JSVM_VM vm; 90 OH_JSVM_GetVM(env, &vm); 91 // 设置两个回调函数,在GC执行之前触发回调 92 int data = 2024; 93 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_BEFORE_GC, OnBeforeGC, JSVM_GC_TYPE_ALL, NULL)); 94 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_BEFORE_GC, OnBeforeGC2, JSVM_GC_TYPE_ALL, (void*)(&data))); 95 // 设置两个回调函数,在GC执行之后触发回调 96 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC, JSVM_GC_TYPE_ALL, NULL)); 97 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, JSVM_GC_TYPE_ALL, NULL)); 98 // (OnAfterGC2, NULL)的组合已经注册过了,重复注册为无效行为 99 if (OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, JSVM_GC_TYPE_ALL, NULL) == JSVM_INVALID_ARG) { 100 add_repeated = true; 101 } 102 // 移除OnAfter2回调函数 103 JSVM_CALL(OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, NULL)); 104 // 重复移除OnAfter2属于无效用法 105 if (OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, NULL) == JSVM_INVALID_ARG) { 106 remove_repeated = true; 107 } 108 // 移除从未设置过的函数属于无效用法 109 if (OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC3, NULL) == JSVM_INVALID_ARG) { 110 remove_notAdded = true; 111 } 112 // 通知引擎当前存在比较大的内存压力,能大概率触发JS引擎的GC流程。 113 JSVM_CALL(OH_JSVM_MemoryPressureNotification(env, JSVM_MEMORY_PRESSURE_LEVEL_CRITICAL)); 114 if ((before_flag1) && 115 (before_flag2) && 116 (after_flag1) && 117 (!after_flag2) && 118 (remove_repeated) && 119 (remove_notAdded) && 120 (add_repeated)) { 121 OH_LOG_INFO(LOG_APP, "JSVM Trigger GC: success"); 122 } else { 123 OH_LOG_ERROR(LOG_APP, "JSVM Trigger GC: failed"); 124 } 125 JSVM_Value checked; 126 OH_JSVM_GetBoolean(env, true, &checked); 127 return checked; 128} 129 130static JSVM_CallbackStruct param[] = { 131 {.data = nullptr, .callback = TriggerGC}, 132}; 133static JSVM_CallbackStruct *method = param; 134 135static JSVM_PropertyDescriptor descriptor[] = { 136 {"triggerGC", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 137}; 138``` 139**样例测试JS** 140```cpp 141const char *srcCallNative = R"JS(triggerGC();)JS"; 142``` 143**执行结果** 144 145在LOG中输出下面结果: 146```cpp 147== before GC == 148gc type: 4 149gc flag: 4 150== before GC2 == 151gc type: 4 152gc flag: 4 153data: 2024 154JSVM Trigger GC: success 155```