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. 27 28You 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. 29 30#### CPP Code 31 32```cpp 33// hello.cpp 34#include <iostream> 35 36#include "jsvmtest.h" 37 38static bool before_flag1 = false; 39static bool before_flag2 = false; 40static bool after_flag1 = false; 41static bool after_flag2 = false; 42 43void OnBeforeGC(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 44{ 45 OH_LOG_INFO(LOG_APP, "== before GC =="); 46 OH_LOG_INFO(LOG_APP, "gc type: %{public}d", gcType); 47 OH_LOG_INFO(LOG_APP, "gc flag: %{public}d", flags); 48 before_flag1 = true; 49} 50 51void OnBeforeGC2(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 52{ 53 OH_LOG_INFO(LOG_APP, "== before GC2 =="); 54 OH_LOG_INFO(LOG_APP, "gc type: %{public}d", gcType); 55 OH_LOG_INFO(LOG_APP, "gc flag: %{public}d", flags); 56 OH_LOG_INFO(LOG_APP, "data: %{public}d", *(int*)data); 57 if (*(int*)data == 2024) { 58 before_flag2 = true; 59 } 60} 61 62void OnAfterGC(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 63{ 64 after_flag1 = true; 65} 66 67void OnAfterGC2(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 68{ 69 after_flag2 = true; 70} 71 72void OnAfterGC3(JSVM_VM vm, JSVM_GCType gcType, JSVM_GCCallbackFlags flags, void *data) 73{ 74 after_flag2 = true; 75} 76 77static JSVM_Value TriggerGC(JSVM_Env env, JSVM_CallbackInfo info) 78{ 79 bool remove_repeated = false; 80 bool remove_notAdded = false; 81 bool add_repeated = false; 82 before_flag1 = false; 83 before_flag2 = false; 84 after_flag1 = false; 85 after_flag2 = false; 86 JSVM_VM vm; 87 OH_JSVM_GetVM(env, &vm); 88 // Register two callbacks to be called before GC. 89 int data = 2024; 90 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_BEFORE_GC, OnBeforeGC, JSVM_GC_TYPE_ALL, NULL)); 91 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_BEFORE_GC, OnBeforeGC2, JSVM_GC_TYPE_ALL, (void*)(&data))); 92 // Register two callbacks to be called after GC. 93 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC, JSVM_GC_TYPE_ALL, NULL)); 94 JSVM_CALL(OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, JSVM_GC_TYPE_ALL, NULL)); 95 // The registration is invalid because (OnAfterGC2, NULL) has been registered. 96 if (OH_JSVM_AddHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, JSVM_GC_TYPE_ALL, NULL) == JSVM_INVALID_ARG) { 97 add_repeated = true; 98 } 99 // Remove the OnAfter2 callback. 100 JSVM_CALL(OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, NULL)); 101 // Repeated removal of OnAfter2 is invalid. 102 if (OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC2, new int(12)) == JSVM_INVALID_ARG) { 103 remove_repeated = true; 104 } 105 // Removing a callback that has never been registered is invalid. 106 if (OH_JSVM_RemoveHandlerForGC(vm, JSVM_CB_TRIGGER_AFTER_GC, OnAfterGC3, NULL) == JSVM_INVALID_ARG) { 107 remove_notAdded = true; 108 } 109 // Notify the system when the JSVM is under high memory pressure, which is likely to trigger GC of the JSVM. 110 JSVM_CALL(OH_JSVM_MemoryPressureNotification(env, JSVM_MEMORY_PRESSURE_LEVEL_CRITICAL)); 111 if ((before_flag1 == true) && 112 (before_flag2 == true) && 113 (after_flag1 == true) && 114 (after_flag2 == false) && 115 (remove_repeated == true) && 116 (remove_notAdded == true) && 117 (add_repeated == true)) { 118 OH_LOG_INFO(LOG_APP, "JSVM Trigger GC: success"); 119 } else { 120 OH_LOG_ERROR(LOG_APP, "JSVM Trigger GC: failed"); 121 } 122 JSVM_Value checked; 123 OH_JSVM_GetBoolean(env, true, &checked); 124 return checked; 125} 126 127static JSVM_CallbackStruct param[] = { 128 {.data = nullptr, .callback = TriggerGC}, 129}; 130static JSVM_CallbackStruct *method = param; 131 132static JSVM_PropertyDescriptor descriptor[] = { 133 {"triggerGC", nullptr, method++, nullptr, nullptr, nullptr, JSVM_DEFAULT}, 134}; 135``` 136#### JS Example 137const char *srcCallNative = R"JS(triggerGC();)JS"; 138 139#### Expected Result 140The following information is displayed in the log: 141== before GC == 142gc type: 4 143gc flag: 4 144== before GC2 == 145gc type: 4 146gc flag: 4 147data: 2024 148JSVM Trigger GC: success 149