1# Triggering GC Using JSVM-API 2 3## Introduction 4 5JSVM-API provides APIs for registering a callback for listening for the memory garbage collection (GC) of a JavaScript VM (JSVM). You can customize logic to perform profiling, debugging, or performance monitoring before or after the GC. 6 7## Basic Concepts 8 9In JS, GC is automatically performed, and users are not aware of the GC behavior of the JSVM. The JS engine enters the prologue phase before each GC, and enters the epilogue phase after each GC. The prologue is the setup phase before the actual GC begins. In this phase, the system prepares for GC. The epilogue is the cleanup phase after the GC. It ensures that the memory is restored to the normal state and ready for the next allocation. In these two phases, the JS engine calls the callbacks registered. You can suspend some tasks, record the memory usage, and optimize performance in the callbacks registered in the prologue phase, and record the memory status after GC and start subsequent tasks in the callbacks registered in the epilogue phase. 10 11JSVM-API provides the **OH_JSVM_AddHandlerForGC** API for registering a callback with a JSVM. You can pass in **JSVM_CB_TRIGGER_BEFORE_GC** to specify the callback in the prologue phase, and pass in **JSVM_CB_TRIGGER_AFTER_GC** to specify the callback in the epilogue phase. You can use **OH_JSVM_RemoveHandlerForGC** to remove a registered callback from a JSVM. 12 13## Available APIs 14 15| API | Description | 16|----------------------------|-------------------------------------| 17| OH_JSVM_AddHandlerForGC | Registers a callback with a JSVM.| 18| OH_JSVM_RemoveHandlerForGC | Removes a registered callback from a JSVM.| 19 20## Example 21 22If you are just starting out with JSVM-API, see [JSVM-API Development Process](use-jsvm-process.md). The following demonstrates only the C++ code involved in GC management. 23 24### OH_JSVM_AddHandlerForGC & OH_JSVM_RemoveHandlerForGC 25 26You can call **OH_JSVM_AddHandlerForGC** multiple times to register callbacks with a JSVM, and all registered callbacks will take effect. The registration behavior uses the callback pointer and **native-data** as the key. If multiple registration behaviors have the same key, the registration will be considered invalid and the **JSVM_INVALID_ARG** error code will be returned. The order in which callbacks are invoked under the same triggering condition does not strictly following the registration order. 27You can use **OH_JSVM_RemoveHandlerForGC** to remove a registered callback from a JSVM. Removing callbacks with the same key will be considered an invalid removal, and the **JSVM_INVALID_ARG** error will be returned. 28 29#### CPP Code 30 31```cpp 32// hello.cpp 33#include <iostream> 34 35static bool before_flag1 = false; 36static bool before_flag2 = false; 37static bool after_flag1 = false; 38static bool after_flag2 = false; 39 40void OnBeforeGC(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 41{ 42 OH_LOG_INFO(LOG_APP, "== before GC =="); 43 OH_LOG_INFO(LOG_APP, "gc type: %{public}d", gcType); 44 OH_LOG_INFO(LOG_APP, "gc flag: %{public}d", flags); 45 before_flag1 = true; 46} 47 48void OnBeforeGC2(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 49{ 50 OH_LOG_INFO(LOG_APP, "== before GC2 =="); 51 OH_LOG_INFO(LOG_APP, "gc type: %{public}d", gcType); 52 OH_LOG_INFO(LOG_APP, "gc flag: %{public}d", flags); 53 OH_LOG_INFO(LOG_APP, "data: %{public}d", *(int*)data); 54 if (*(int*)data == 2024) { 55 before_flag2 = true; 56 } 57} 58 59void OnAfterGC(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 60{ 61 after_flag1 = true; 62} 63 64void OnAfterGC2(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 65{ 66 after_flag2 = true; 67} 68 69void OnAfterGC3(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 70{ 71 after_flag2 = true; 72} 73 74static JSVM_Value TriggerGC(JSVM_Env env, JSVM_CallbackInfo info) 75{ 76 bool remove_repeated = false; 77 bool remove_notAdded = false; 78 bool add_repeated = false; 79 before_flag1 = false; 80 before_flag2 = false; 81 after_flag1 = false; 82 after_flag2 = false; 83 JSVM_VM vm; 84 OH_JSVM_GetVM(env, &vm); 85 // Register two callbacks to be called before GC. 86 int data = 2024; 87 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_BEFORE_GC, OnBeforeGC, JSVM_GC_TYPE_ALL, NULL)); 88 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_BEFORE_GC, OnBeforeGC2, JSVM_GC_TYPE_ALL, (void*)(&data))); 89 // Register two callbacks to be called after GC. 90 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC, JSVM_GC_TYPE_ALL, NULL)); 91 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, JSVM_GC_TYPE_ALL, NULL)); 92 // The registration is invalid because (OnAfterGC2, NULL) has been registered. 93 if (OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, JSVM_GC_TYPE_ALL, NULL) == JSVM_INVALID_ARG) { 94 add_repeated = true; 95 } 96 // Remove the OnAfter2 callback. 97 JSVM_CALL(OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, NULL)); 98 // Repeated removal of OnAfter2 is invalid. 99 if (OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, new int(12)) == JSVM_INVALID_ARG) { 100 remove_repeated = true; 101 } 102 // Removing a callback that has never been registered is invalid. 103 if (OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC3, NULL) == JSVM_INVALID_ARG) { 104 remove_notAdded = true; 105 } 106 // Notify the system when the JSVM is under high memory pressure, which is likely to trigger GC of the JSVM. 107 JSVM_CALL(OH_JSVM_MemoryPressureNotification(env, JSVM_MEMORY_PRESSURE_LEVEL_CRITICAL)); 108 if ((before_flag1 == true) && 109 (before_flag2 == true) && 110 (after_flag1 == true) && 111 (after_flag2 == false) && 112 (remove_repeated == true) && 113 (remove_notAdded == true) && 114 (add_repeated == true)) { 115 OH_LOG_INFO(LOG_APP, "JSVM Trigger GC: success"); 116 } else { 117 OH_LOG_ERROR(LOG_APP, "JSVM Trigger GC: failed"); 118 } 119 JSVM_Value checked; 120 OH_JSVM_GetBoolean(env, true, &checked); 121 return checked; 122} 123 124static JSVM_CallbackStruct param[] = { 125 {.data = nullptr, .callback = TriggerGC}, 126}; 127static JSVM_CallbackStruct *method = param; 128 129static JSVM_PropertyDescriptor descriptor[] = { 130 {"triggerGC", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 131}; 132``` 133#### JS Example 134const char *srcCallNative = R"JS(triggerGC();)JS"; 135 136#### Expected Result 137The following information is displayed in the log: 138== before GC == 139gc type: 4 140gc flag: 4 141== before GC2 == 142gc type: 4 143gc flag: 4 144data: 2024 145JSVM Trigger GC: success 146