• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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