|
1 | 1 | [//]: # (title: Kotlin/Native memory management)
|
2 | 2 |
|
3 |
| -Kotlin/Native uses a modern memory manager that is similar to the JVM, Go, and other mainstream technologies, including |
4 |
| -the following features: |
5 | 3 |
|
6 |
| -* Objects are stored in a shared heap and can be accessed from any thread. |
7 |
| -* Tracing garbage collection (GC) is performed periodically to collect objects that are not reachable from the "roots", |
8 |
| - like local and global variables. |
| 4 | +* Kotlin/Native's memory manager |
| 5 | + * == Java, Go or Swift's memory manager |
| 6 | + * 👀features👀 |
| 7 | + * Objects |
| 8 | + * are stored | shared heap |
| 9 | + * -- can be accessed from -- ANY thread |
| 10 | + * Tracing garbage collection (GC) -- is performed -- periodically collecting objects / NOT reachable from the "roots" (_Example:_ |
| 11 | + like local and global variables) |
9 | 12 |
|
10 | 13 | ## Garbage collector
|
11 | 14 |
|
12 |
| -Kotlin/Native's GC algorithm is constantly evolving. Currently, it functions as a stop-the-world mark and concurrent sweep |
13 |
| -collector that does not separate the heap into generations. |
| 15 | +* Kotlin/Native's GC algorithm is constantly evolving |
| 16 | + * stop-the-world mark + concurrent sweep collector / heap is NOT separated into generations ❓ |
| 17 | + * stop-the-world mark == full parallel mark / combines paused mutators + GC thread + optional marker threads |
| 18 | + * | marking process, by default, paused mutators + >=1 GC thread |
| 19 | + * if you want to disable the full parallel mark -> pass `-Xbinary=gcMarkSingleThreaded=true` compilation option |
| 20 | + * may increase -- the -- pause time of the garbage collector |
| 21 | + * GC thread |
| 22 | + * == GC is |
| 23 | + * executed | separate thread |
| 24 | + * started -- based on the -- timer & memory pressure heuristics |
14 | 25 |
|
15 |
| -The GC uses a full parallel mark that combines paused mutators, the GC thread, and optional marker threads to process |
16 |
| -the mark queue. By default, paused mutators and at least one GC thread participate in the marking process. |
17 |
| -You can disable the full parallel mark with the `-Xbinary=gcMarkSingleThreaded=true` compilation option. |
18 |
| -However, this may increase the pause time of the garbage collector. |
| 26 | +* once the marking phase is completed -> |
| 27 | + * GC processes weak references & |
| 28 | + * nullifies reference -- points to an -- unmarked object |
| 29 | +* if you want to decrease the GC pause time -> enable the concurrent processing of weak references -- via -- `-Xbinary=concurrentWeakSweep=true` compilation option |
19 | 30 |
|
20 |
| -When the marking phase is completed, the GC processes weak references and nullifies reference points to an unmarked object. |
21 |
| -To decrease the GC pause time, you can enable the concurrent processing of weak references by using |
22 |
| -the `-Xbinary=concurrentWeakSweep=true` compilation option. |
23 |
| - |
24 |
| -The GC is executed on a separate thread and started based on the timer |
25 |
| -and memory pressure heuristics. Alternatively, it can be [called manually](#enable-garbage-collection-manually). |
| 31 | +* GC can be [called manually](#enable-garbage-collection-manually) |
26 | 32 |
|
27 | 33 | ### Enable garbage collection manually
|
28 | 34 |
|
29 |
| -To force-start the garbage collector, call `kotlin.native.internal.GC.collect()`. This method triggers a new collection |
30 |
| -and waits for its completion. |
| 35 | +* call `kotlin.native.internal.GC.collect()` |
| 36 | + * -> triggers a new collection & waits for its completion |
31 | 37 |
|
32 | 38 | ### Monitor GC performance
|
33 | 39 |
|
34 |
| -To monitor the GC performance, you can look through its logs and diagnose issues. To enable logging, |
35 |
| -set the following compiler option in the Gradle build script: |
36 |
| - |
37 |
| -```none |
38 |
| --Xruntime-logs=gc=info |
39 |
| -``` |
40 |
| - |
41 |
| -Currently, the logs are only printed to `stderr`. |
42 |
| - |
43 |
| -On Apple platforms, you can take advantage of the Xcode Instruments toolkit to debug iOS app performance. |
44 |
| -The garbage collector reports pauses with signposts available in Instruments. |
45 |
| -Signposts enable custom logging within your app, allowing you to check if a GC pause corresponds to an application freeze. |
46 |
| - |
47 |
| -To track GC-related pauses in your app: |
| 40 | +* if you want to enable logging -> set the following compiler option | Gradle build script |
48 | 41 |
|
49 |
| -1. Open Xcode, go to **Product** | **Profile** or press <shortcut>Cmd + I</shortcut>. This action compiles your app and |
50 |
| - launches Instruments. |
51 |
| -2. In the template selection, select **os_signpost**. |
52 |
| -3. Configure it by specifying `org.kotlinlang.native.runtime` as **subsystem** and `safepoint` as **category**. |
53 |
| -4. Click the red record button to run your app and start recording signpost events: |
| 42 | + ```none |
| 43 | + -Xruntime-logs=gc=info |
| 44 | + |
| 45 | + // default |
| 46 | + //-Xruntime-logs=gc=error |
| 47 | + ``` |
54 | 48 |
|
55 |
| - {width=700} |
| 49 | +* | Apple platforms, use Xcode Instruments toolkit |
| 50 | + * way to track GC-related pauses |
| 51 | + 1. Open Xcode, go to **Product** | **Profile** or press <shortcut>Cmd + I</shortcut> |
| 52 | + 1. -> compiles your app & launches Instruments |
| 53 | + 2. | template selection, select **os_signpost** |
| 54 | + 3. specify `org.kotlinlang.native.runtime` as **subsystem** & `safepoint` as **category** |
| 55 | + 4. Click the red record button to run your app and start recording signpost events |
56 | 56 |
|
57 |
| - Here, each blue blob on the lowest graph represents a separate signpost event, which is a GC pause. |
58 |
| - |
59 |
| -The feature is enabled by default. However, you can disable it with the `-Xbinary=enableSafepointSignposts=false` |
60 |
| -compiler option. |
| 57 | +  |
| 58 | + * previous feature |
| 59 | + * enabled, by default |
| 60 | + * if you want to disable -> specify `-Xbinary=enableSafepointSignposts=false` compiler option |
61 | 61 |
|
62 | 62 | ### Disable garbage collection
|
63 | 63 |
|
64 |
| -It's recommended to keep GC enabled. However, you can disable it in certain cases, such as for testing purposes or |
65 |
| -if you encounter issues and have a short-lived program. To do so, set the following compilation flag in the Gradle |
66 |
| -build script: |
| 64 | +* use cases to disable garbage collection |
| 65 | + * testing purposes |
| 66 | + * if you encounter issues & have a short-lived program |
| 67 | +* | Gradle build script |
67 | 68 |
|
68 |
| -```none |
69 |
| --Xgc=noop |
70 |
| -``` |
| 69 | + ```none |
| 70 | + -Xgc=noop |
| 71 | + ``` |
71 | 72 |
|
72 |
| -> With this option enabled, the GC doesn't collect Kotlin objects, so memory consumption will keep rising as long as the |
73 |
| -> program runs. Be careful not to exhaust the system memory. |
74 |
| -> |
75 |
| -{type="warning"} |
| 73 | +* if it's disabled -> memory consumption will keep rising -> 👀careful NOT exhaust the system memory 👀 |
76 | 74 |
|
77 | 75 | ## Memory consumption
|
78 | 76 |
|
79 |
| -Kotlin/Native uses its own [memory allocator](https://github.com/JetBrains/kotlin/blob/master/kotlin-native/runtime/src/alloc/custom/README.md). |
80 |
| -It divides system memory into pages, allowing independent sweeping in consecutive order. Each allocation becomes a memory |
81 |
| -block within a page, and the page keeps track of block sizes. Different page types are optimized for various allocation |
82 |
| -sizes. The consecutive arrangement of memory blocks ensures efficient iteration through all allocated blocks. |
83 |
| - |
84 |
| -When a thread allocates memory, it searches for a suitable page based on the allocation size. Threads maintain a set of |
85 |
| -pages for different size categories. Typically, the current page for a given size can accommodate the allocation. |
86 |
| -If not, the thread requests a different page from the shared allocation space. This page may already be available, |
87 |
| -require sweeping, or have to be created first. |
88 |
| - |
89 |
| -The Kotlin/Native memory allocator comes with protection against sudden spikes in memory allocations. It prevents |
90 |
| -situations where the mutator starts to allocate a lot of garbage quickly and the GC thread cannot keep up with it, |
91 |
| -making the memory usage grow endlessly. In this case, the GC forces a stop-the-world phase until the iteration is completed. |
92 |
| - |
93 |
| -You can monitor memory consumption yourself, check for memory leaks, and adjust memory consumption. |
| 77 | +* 💡Kotlin/Native uses its OWN [memory allocator](https://github.com/JetBrains/kotlin/blob/master/kotlin-native/runtime/src/alloc/custom/README.md) 💡/ |
| 78 | + * 👀system memory -- is divided into -- pages 👀 |
| 79 | + * -> sweeping |
| 80 | + * independent |
| 81 | + * in consecutive order |
| 82 | + * EACH allocation == memory block | page |
| 83 | + * the page -- keeps track of -- block sizes |
| 84 | + * DIFFERENT page types -- are optimized for -- various allocation sizes |
| 85 | + * consecutive arrangement of memory blocks -> efficient iteration | ALL allocated blocks |
| 86 | + * includes protection -- against -- sudden spikes | memory allocations |
| 87 | + * -> prevents certain situations |
| 88 | + * _Example:_ mutator starts to allocate a lot of garbage quickly & the GC thread can NOT keep up with it == memory usage grow endlessly |
| 89 | + * -> GC forces a stop-the-world phase | UNTIL the iteration is completed |
| 90 | +
|
| 91 | +* if a thread allocates memory -> the thread -- searches for a -- suitable page / -- based on the -- allocation size |
| 92 | + * threads maintain a set of pages / DIFFERENT size categories |
| 93 | + * current page / given size -- can accommodate the -- allocation |
| 94 | + * if not -> the thread -- from the shared allocation space, requests a -- different page / |
| 95 | + * this page MAY |
| 96 | + * already be available, |
| 97 | + * require sweeping, or |
| 98 | + * have to be created first |
94 | 99 |
|
95 | 100 | ### Check for memory leaks
|
96 | 101 |
|
| 102 | +* TODO: |
97 | 103 | To access the memory manager metrics, call `kotlin.native.internal.GC.lastGCInfo()`. This method returns statistics for the last
|
98 | 104 | run of the garbage collector. The statistics can be useful for:
|
99 | 105 |
|
|
0 commit comments