• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# GC
2
3Garbage Collection (GC) is a process that identifies and reclaims memory no longer in use by a program. It aims to free up unused memory space. Modern programming languages implement two primary types of GC algorithms: reference counting and tracing GC.
4
5## GC Algorithm Overview
6
7### Types of GC
8
9#### Reference Counting
10When object A is referenced by object B, A's reference count increases by 1. Conversely, when the reference is removed, A's reference count decreases by 1. When A's reference count reaches 0, object A is reclaimed.
11
12- Pros: Reference counting is simple to implement and allows for immediate memory reclamation, avoiding a dedicated Stop The World (STW) phase where the application is paused.
13- Cons: The extra counting step during object manipulation increases the overhead of memory allocation and assignment, affecting performance. Most critically, it fails to handle circular references.
14
15```
16class Parent {
17  constructor() {
18    this.child = null;
19  }
20  child: Child | null = null;
21}
22
23class Child {
24  constructor() {
25    this.parent = null;
26  }
27  parent: Parent | null = null;
28}
29
30function main() {
31  let parent: Parent = new Parent();
32  let child: Child = new Child();
33  parent.child = child;
34
35}
36```
37In the example above, parent holds a reference to child, and child holds a reference to parent. This circular reference means that neither object's reference count will reach zero, even after the **main** function ends, resulting in a memory leak.
38
39#### Tracking GC
40
41![image](./figures/tracing-gc.png)
42
43Tracing GC identifies live objects by traversing the object graph starting from root objects, which include stack objects and global objects that are guaranteed to be alive. Objects referenced by these root objects are also considered live. The traversal marks all reachable objects (blue) as live, whereas unreachable objects (yellow) are considered garbage.
44
45- Pros: Tracing GC solves the circular reference problem and does not incur additional overhead during memory allocation and assignment.
46- Cons: Tracing GC is more complex than reference counting and introduces a brief STW phase. Additionally, GC can be delayed, leading to floating garbage.
47
48Given the limitations of reference counting, especially the critical issue of circular references, ArkTS Runtime uses tracing GC.
49
50### Types of Tracing GC
51Tracing GC algorithms identify garbage by traversing the object graph. Based on the collection method, tracing GC can be categorized into three basic types: mark-sweep, mark-copy, and mark-compact. In the diagrams below, blue indicates live objects, whereas yellow indicates garbage.
52
53#### Mark-Sweep Collection
54
55![image](./figures/mark-clearn.png)
56
57After traversing the object graph, the algorithm clears the contents of unreachable objects and places them in a free list for future allocations.
58This approach is highly efficient as it does not move objects. However, it can lead to memory fragmentation, reducing allocation efficiency and potentially preventing the allocation of large objects despite ample free memory.
59
60#### Mark-Copy Collection
61
62![image](./figures/mark-copy.png)
63
64During the traversal of the object graph, reachable objects are copied to a new, contiguous memory space. After the traversal, the old memory space is reclaimed entirely.
65This approach eliminates memory fragmentation and completes the GC process in a single traversal, making it efficient. However, it requires reserving half of the memory space to ensure all live objects can be copied, resulting in lower space utilization.
66
67#### Mark-Compact Collection
68
69![image](./figures/mark-shuffle.png)
70
71After the traversal, live objects (blue) are copied to the beginning of the current space (or a designated area), and the copied objects are reclaimed and placed in the free list.
72This approach addresses memory fragmentation without wasting half of the memory space, though it incurs slightly higher performance overhead when compared with mark-copy collection.
73
74### HPP GC
75
76High Performance Partial Garbage Collection (HPP GC) is designed for high performance in partial GC, leveraging generational models, hybrid algorithms, and optimized GC processes. In terms of algorithms, HPP GC uses different collection approaches based on different object regions.
77
78#### Generational Model
79
80ArkTS Runtime uses a traditional generational model, categorizing objects based on their lifetimes. Given that most newly allocated objects are short-lived and collected during the first GC cycle, whereas objects surviving multiple GC cycles are likely to remain alive, ArkTS Runtime divides objects into young and old generations, allocating them to separate spaces.
81
82![image](./figures/generational-model.png)
83
84Newly allocated objects are placed in the **from** space of Young Space. After surviving one GC cycle, they are moved to the **to** space, which then swaps roles with the **from** space. Objects surviving another GC cycle are copied to Old Space.
85
86#### Hybrid Algorithm
87
88HPP GC employs a hybrid algorithm combining mark-copy, mark-compact, and mark-sweep, tailored to the characteristics of young and old generation objects.
89
90- Mark-copy for young generation
91Given the short lifetimes, small size, and frequent collection of young generation objects, ArkTS Runtime uses the mark-copy algorithm to efficiently reclaim memory for these objects.
92- Mark-compact + mark-sweep for old generation
93Based on the characteristics of old generation objects, a heuristic collection set (CSet) algorithm is used. The fundamental idea behind this algorithm is to collect the sizes of live objects in each region during the marking phase. During the collection phase, ArkTS Runtime uses mark-compact for regions with fewer live objects and lower collection costs, but mark-sweep for the remaining regions.
94
95The collection policies are as follows:
96
97- Identifies regions with live object sizes below a threshold, places them in the initial CSet, and sorts them by liveness
98
99(survival rate = live object size/region size).
100
101- Selects a final CSet based on a predefined number of regions for compaction.
102
103- Sweeps the remaining regions.
104
105This heuristic approach combines the benefits of mark-compact and mark-sweep algorithms, addressing memory fragmentation while maintaining performance.
106
107#### Process Optimization
108
109HPP GC introduces extensive concurrency and parallelism optimizations to minimize the impact on application performance. The GC process includes concurrent and parallel marking, sweeping, evacuation, updating, and clearing tasks.
110
111
112
113## Heap Structure and Parameters
114
115### Heap Structure
116
117![image](./figures/gc-heap-space.png)
118
119- Semi Space: space for storing young generation, that is, newly created objects with low survival rates. The copying algorithm is used to reclaim memory.
120- Old Space: space for storing old generation, that is, objects that survive multiple GC cycles. Multiple algorithms are used for memory reclamation.
121- Huge Object Space: dedicated regions for storing large objects.
122- Read Only Space: space for storing read-only data at runtime.
123- Non-Movable Space: space for storing non-movable objects.
124- Snapshot Space: space for storing heap snapshots.
125- Machine Code Space: space for storing machine codes.
126
127Each space is managed in regions, which are the units requested from the memory allocator.
128
129### Parameters
130
131> **NOTE**
132>
133> Parameters not marked as configurable are system-defined and cannot be adjusted by developers.
134
135Based on the total heap size ranges (64 MB to 128 MB, 128 MB to 256 MB, or greater than 256 MB), the system sets different sizes for the following parameters. If a parameter has a single value in the range, it remains constant regardless of the total heap size. The default total heap size for mobile phones is greater than 256 MB.
136You can use related APIs to query memory information by referring to [HiDebug API Reference](../reference/apis-performance-analysis-kit/js-apis-hidebug.md).
137
138#### Heap Size Parameters
139
140| Parameter| Value or Value Range| Description|
141| --- | --- | :--- |
142| HeapSize | 448 MB| Default total heap size for the main thread. The value is adjusted for low-memory devices based on the actual memory pool size.|
143| SemiSpaceSize | 2–4 MB/2–8 MB/2–16 MB| Size of Semi Space.|
144| NonmovableSpaceSize | 2 MB/6 MB/64 MB | Size of Non-Movable Space.|
145| SnapshotSpaceSize | 512 KB| Size of Snapshot Space.|
146| MachineCodeSpaceSize | 2 MB| Size of Machine Code Space.|
147
148#### Worker Thread Heap Limit
149
150| Parameter| Value| Description|
151| --- | --- | --- |
152| HeapSize  | 768 MB | Heap size for worker threads.|
153
154#### Parameters of Semi Space
155
156The heap contains two Semi Spaces for copying.
157
158| Parameter| Value or Value Range| Description|
159| --- | --- | :--- |
160| semiSpaceSize | 2–4 MB/2–8 MB/2–16 MB| Size of Semi Space. The value varies according to the total heap size.|
161| semiSpaceTriggerConcurrentMark | 1 M/1.5 M/1.5 M| Threshold for independently triggering concurrent marking in Semi Space for the first time.|
162| semiSpaceStepOvershootSize| 2 MB | Maximum overshoot size of Semi Space.|
163
164#### Parameters of Old Space and Huge Object Space
165
166Both spaces are initialized to the remaining unallocated heap size. By default, the upper limit of OldSpaceSize of the main thread on mobile phones approaches 350 MB.
167
168| Parameter| Value| Description|
169| --- | --- | :--- |
170| oldSpaceOvershootSize | 4 MB/8 MB/8 MB | Maximum overshoot size of Old Space.|
171
172#### Parameters of Other Spaces
173
174| Parameter| Value| Description|
175| --- | --- | :--- |
176| defaultReadOnlySpaceSize | 256 KB | Default size of Read Only Space.|
177| defaultNonMovableSpaceSize | 2 MB/6 MB/64 MB | Default size of Non-Movable Space.|
178| defaultSnapshotSpaceSize | 512 KB/512 KB/ 4 MB | Default size of Snapshot Space.|
179| defaultMachineCodeSpaceSize | 2 MB/2 MB/8 MB | Default size of Machine Code Space.|
180
181#### Interpreter Stack Size
182
183| Parameter| Value| Description|
184| --- | --- | --- |
185| maxStackSize | 128 KB| Maximum frame size of the interpreter stack.|
186
187#### Concurrency Parameters
188
189| Parameter| Value| Description|
190| --- | ---: | --- |
191| gcThreadNum | 7 | Number of GC threads. The default value is 7. You can set this parameter using **gc-thread-num**.|
192| MIN_TASKPOOL_THREAD_NUM | 3 | Minimum number of threads in the thread pool.|
193| MAX_TASKPOOL_THREAD_NUM | 7 | Maximum number of threads in the thread pool.|
194
195Note: The thread pool is used to execute concurrent tasks in the GC process. During thread pool initialization, all the three parameters need to be considered. If **gcThreadNum** is negative, the number of threads in the initialized thread pool is the number of CPU cores divided by 2.
196
197#### Other Parameters
198
199| Parameter| Value| Description|
200| --- | --- | --- |
201| minAllocLimitGrowingStep | 2 M/4 M/8 M| Minimum growth step of **oldSpace**, **heapObject**, and **globalNative** when the heap size is recalculated.|
202| minGrowingStep | 4 M/8 M/16 M| Minimum growth step of **oldSpace**.|
203| longPauseTime | 40 ms| Threshold for identifying long GC pauses, which trigger detailed GC log printing for analysis. It can be set using **gc-long-paused-time**.|
204
205### Additional: The native total memory limit for ArrayBuffer within a single VM is set to 4 GB.
206
207## GC Process
208
209
210![image](./figures/gc-process.png)
211
212### Types of HPP GC
213
214#### Young GC
215
216- **When to trigger**: The young GC threshold ranges from 2 MB to 16 MB, and it can be adjusted dynamically based on the allocation speed and survival rate.
217- **Description**: primarily collects newly allocated objects in Semi Space.
218- **Scenario**: foreground
219- **Log keywords**: [ HPP YoungGC ]
220
221#### Old GC
222
223- **When to trigger**: The old GC threshold ranges from 20 MB to 300 MB. Typically, the threshold of the first old GC is about 20 MB, and the threshold for subsequent old GC operations is adjusted based on the survival rate and memory usage.
224- **Description**: compacts and compresses the young generation space and parts of the old generation space while sweeping other spaces. It occurs less frequently than young GC, with a longer duration (approximately 5 ms to 10 ms) due to full marking.
225- **Scenario**: foreground
226- **Log keywords**: [ HPP OldGC ]
227
228#### Full GC
229
230- **When to trigger**: Full GC is not triggered based on the memory threshold. After the application transitions to the background, full GC is triggered if the predicted reclaimable object size exceeds 2 MB. You can also trigger full GC using the DumpHeapSnapshot and AllocationTracker tools or calling native interfaces and JS/TS interfaces.
231- **Description**: fully compacts both young and old generations, maximizing memory reclamation in performance-insensitive scenarios.
232- **Scenario**: background
233- **Log keywords**: [ CompressGC ]
234
235Subsequent Smart GC or IDLE GC selections are made from the above three types of GC.
236
237### Trigger Strategies
238
239#### Space Threshold Triggering
240
241- Functions: **AllocateYoungOrHugeObject**, **AllocateHugeObject**, and other allocation-related functions
242- Restriction parameters: corresponding space thresholds
243- Description: GC is triggered when object allocation reaches the space threshold.
244- Log keywords: **GCReason::ALLOCATION_LIMIT**
245
246#### Native Binding Size Triggering
247
248- Functions: **GlobalNativeSizeLargerThanLimit**
249- Restriction parameters: **globalSpaceNativeLimit**
250- Description: It affects the decision for performing full marking and concurrent marking.
251
252#### Background Switch Triggering
253
254- Functions: **ChangeGCParams**
255- Description: Full GC is triggered when the application switches to the background.
256- Log keywords: **app is inBackground**, **app is not inBackground**, and
257  **GCReason::SWITCH_BACKGROUND**
258
259### Execution Strategies
260
261#### Concurrent Marking
262
263- Function: **TryTriggerConcurrentMarking**
264- Description: attempts to trigger concurrent marking and delegate the task of marking objects to the thread pool to reduce the suspension time of the UI main thread.
265- Log keywords: **fullMarkRequested**, **trigger full mark**, **Trigger the first full mark**, **Trigger full mark**, **Trigger the first semi mark**, and **Trigger semi mark**
266
267#### Adjusting Thresholds Before and After New Space GC
268
269- Function: **AdjustCapacity**
270- Description: adjusts the Semi Space trigger threshold after GC to optimize space structure.
271- Log keywords: There is no direct log. The GC statistics logs show dynamic adjustments to young space thresholds before and after GC.
272
273#### Adjusting Threshold After First Old GC
274
275- Function: **AdjustOldSpaceLimit**
276- Description: adjusts the Old Space threshold based on the minimum growth step and average survival rate.
277- Log keywords: **"AdjustOldSpaceLimit oldSpaceAllocLimit_: "<< oldSpaceAllocLimit <<" globalSpaceAllocLimit_: " << globalSpaceAllocLimit_;**
278
279#### Adjusting Old Space/Global Space Thresholds and Growth Factors After Subsequent Old GCs
280
281- Function: **RecomputeLimits**
282- Description: recalculates and adjusts **newOldSpaceLimit**, **newGlobalSpaceLimit**, **globalSpaceNativeLimit**, and growth factors based on current GC statistics.
283- Log keywords: **"RecomputeLimits oldSpaceAllocLimit_: "<< newOldSpaceLimit_ <<" globalSpaceAllocLimit_: "<< globalSpaceAllocLimit_ <<" globalSpaceNativeLimit_: "<< globalSpaceNativeLimit_;**
284
285#### CSet Selection Strategies for Partial GC
286
287- Function: **OldSpace::SelectCSet()**
288- Description: selects regions with fewer live objects and lower collection costs for partial GC.
289- Log keywords: **Select CSet failure: number is too few**,
290  **"Max evacuation size is 6_MB. The CSet region number: " << selectedRegionNumber;**,
291  and **"Select CSet success: number is " << collectRegionSet_.size();**
292
293## SharedHeap
294
295### Shared Heap Structure
296
297![image](./figures/gc-shared-heap.png)
298
299- Shared Old Space: shared space for storing general shared objects. The young generation and old generation are not distinguished in the shared heap.
300- Shared Huge Object Space: shared space for storing large objects. A separate region is used for each large object.
301- Shared Read Only Space: shared space for storing read-only data at runtime.
302- Shared Non-Movable Space: shared space for storing non-movable objects.
303
304Note: The shared heap is designed for objects shared across threads to improve efficiency and save memory. It does not belong to any single thread and stores objects with shared value. It typically has higher survival rates and does not involve Semi Space.
305
306## Features
307
308### Smart GC
309
310#### Description
311
312In performance-sensitive scenarios, the GC trigger threshold of the JS thread is temporarily adjusted to the maximum JS heap size (448 MB by default), minimizing GC-triggered frame drops. (Smart GC does not take effect for the Worker thread and TaskPool thread.) However, if a performance-sensitive scenario persists too long and object allocation reaches the maximum heap size, GC is triggered, potentially resulting in longer GC times due to accumulated objects.
313
314#### Performance-Sensitive Scenarios
315
316- Application cold start
317- Application scrolling
318- Page transitions via clicks
319- Jumbo frame
320
321Currently, this feature is managed by the system, and third-party applications do not have APIs to directly call this feature.
322
323Log keyword: **SmartGC**
324
325#### Interaction Process
326
327![image](./figures/gc-smart-feature.png)
328
329Mark performance-sensitive scenarios by tagging the heap upon entry and exit to avoid unnecessary GCs and maintain high performance.
330
331## Log Interpretation
332
333### Enabling Full Logs
334
335By default, detailed GC logs are printed only when GC duration exceeds 40 ms. To enable logs for all GC executions, run commands on the device.
336
337**Example**
338
339```shell
340# Enable full GC logs with parameter 0x905d. Disable full GC logs and revert to the default value (0x105c).
341hdc shell param set persist.ark.properties 0x905d
342# Reboot to apply changes.
343hdc shell reboot
344```
345
346### Typical Logs
347
348The following logs represent a complete GC execution, with variations based on the type of GC. You can search for the keyword [gc] in the exported log file to view GC-related logs. You can also check for the keyword ArkCompiler to view more comprehensive VM-related logs.
349
350```
351// Pre-GC object size (region size) -> Post-GC object size (region size), total duration (+concurrentMark duration), GC trigger reason.
352C03F00/ArkCompiler: [gc]  [ CompressGC ] 26.1164 (35) -> 7.10049 (10.5) MB, 160.626(+0)ms, Switch to background
353// Various states during GC execution and application name.
354C03F00/ArkCompiler: [gc] IsInBackground: 1; SensitiveStatus: 0; OnStartupEvent: 0; BundleName: com.huawei.hmos.filemanager;
355// Duration statistics for each GC phase.
356C03F00/ArkCompiler: [gc] /***************** GC Duration statistic: ****************/
357C03F00/ArkCompiler: [gc] TotalGC:                 160.626 ms
358C03F00/ArkCompiler: Initialize:              0.179   ms
359C03F00/ArkCompiler: Mark:                    159.204 ms
360C03F00/ArkCompiler: MarkRoots:               6.925   ms
361C03F00/ArkCompiler: ProcessMarkStack:        158.99  ms
362C03F00/ArkCompiler: Sweep:                   0.957   ms
363C03F00/ArkCompiler: Finish:                  0.277   ms
364// Memory usage statistics after GC.
365C03F00/ArkCompiler: [gc] /****************** GC Memory statistic: *****************/
366C03F00/ArkCompiler: [gc] AllSpaces        used:  7270.9KB     committed:   10752KB
367C03F00/ArkCompiler: ActiveSemiSpace  used:       0KB     committed:     256KB
368C03F00/ArkCompiler: OldSpace         used:  4966.9KB     committed:    5888KB
369C03F00/ArkCompiler: HugeObjectSpace  used:    2304KB     committed:    2304KB
370C03F00/ArkCompiler: NonMovableSpace  used:       0KB     committed:    2304KB
371C03F00/ArkCompiler: MachineCodeSpace used:       0KB     committed:       0KB
372C03F00/ArkCompiler: HugeMachineCodeSpace used:       0KB     committed:       0KB
373C03F00/ArkCompiler: SnapshotSpace    used:       0KB     committed:       0KB
374C03F00/ArkCompiler: AppSpawnSpace    used: 4736.34KB     committed:    4864KB
375C03F00/ArkCompiler: [gc] Anno memory usage size:  45      MB
376C03F00/ArkCompiler: Native memory usage size:2.99652 MB
377C03F00/ArkCompiler: NativeBindingSize:       0.577148KB
378C03F00/ArkCompiler: ArrayBufferNativeSize:   0.0117188KB
379C03F00/ArkCompiler: RegExpByteCodeNativeSize:0.280273KB
380C03F00/ArkCompiler: ChunkNativeSize:         19096   KB
381C03F00/ArkCompiler: [gc] Heap alive rate:         0.202871
382// Summary statistics for this type of GC in the VM.
383C03F00/ArkCompiler: [gc] /***************** GC summary statistic: *****************/
384C03F00/ArkCompiler: [gc] CompressGC occurs count  6
385C03F00/ArkCompiler: CompressGC max pause:    2672.33 ms
386C03F00/ArkCompiler: CompressGC min pause:    160.626 ms
387C03F00/ArkCompiler: CompressGC average pause:1076.06 ms
388C03F00/ArkCompiler: Heap average alive rate: 0.635325
389```
390
391- GC type, which can be [HPP YoungGC], [HPP OldGC], [CompressGC], and [SharedGC].
392- **TotalGC**: total duration. The following lists the duration for each phase, including Initialize, Mark, MarkRoots, ProcessMarkStack, Sweep, and Finish. The actual phases may vary depending on the GC process.
393- **IsInBackground**: specifies whether the application is in the background (**1**) or foreground (**0**).
394- **SensitiveStatus**: specifies whether the application is in a sensitive scenario (**1**) or not (**0**).
395- **OnStartupEvent**: specifies whether the application is in a cold start scenario (**1**) or not (**0**).
396- **used**: actual memory usage of allocated objects.
397- **committed**: actual memory allocated to the heap. Since memory spaces are allocated in regions that are not always fully utilized by objects, **committed** is greater than or equal to **used**. For Huge Space, these values are equal because each object occupies a separate region.
398- **Anno memory usage size**: total memory usage of all heaps in the process, including heap and shared heap.
399- **Native memory usage size**: total native memory usage of the process.
400- **NativeBindingSize**: native memory usage of objects bound to the heap.
401- **ArrayBufferNativeSize**: native memory usage of array buffers requested by the process.
402- **RegExpByteCodeNativeSize**: native memory usage of regular expression bytecode requested by the process.
403- **ChunkNativeSize**: native memory usage of chunks requested by the process.
404- **Heap alive rate**: survival rate of objects in the heap.
405
406## GC Developer Debugging Interfaces
407
408> **NOTE**
409>
410> The following interfaces are for debugging purposes only and are not official SDK interfaces. They should not be used in production applications.
411
412### ArkTools.hintGC()
413
414- Invocation: **ArkTools.hintGC()**
415- Type: JS interface
416- Description: triggers the VM to assess whether a full GC should be executed. Full GC is initiated in the background or if the expected memory survival rate is below a threshold. It will not trigger in sensitive scenarios.
417- Use case: developers prompting the system to perform GC.
418- Log keywords: There is no direct log. Only external trigger (**GCReason::TRIGGER_BY_JS**) can be found.
419
420
421Usage example:
422
423```
424// Declare the interface first.
425declare class ArkTools {
426     static hintGC(): void;
427}
428
429@Entry
430@Component
431struct Index {
432  @State message: string = 'Hello World';
433  build() {
434  Row() {
435    Column() {
436      Text(this.message)
437        .fontSize(50)
438        .fontWeight(FontWeight.Bold)
439      Button("Trigger Hint GC").onClick((event: ClickEvent) => {
440          ArkTools.hintGC(); // Call the method directly.
441      })
442    }
443    .width('100%')
444  }
445  .height('100%')
446}
447}
448```
449