Kotlin 内存管理:垃圾回收器的工作原理

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Kotlin 中的内存与垃圾回收器:如何避免内存泄漏并保持性能

\n\n

您是否曾想过,您的 Kotlin 应用程序的内存都去哪儿了?代码看起来完美无缺,协程运行流畅,但一小时后程序开始“卡顿”或崩溃并抛出 OutOfMemoryError。熟悉的感觉吗?欢迎加入那些想了解 Kotlin 如何管理内存以及为什么垃圾回收器不是敌人,而是您最好的朋友(如果您知道如何与之相处)的俱乐部。

\n\n

在本文中,我们将深入探讨 Kotlin 内存管理 的主题,并分析 Kotlin 垃圾回收器 在不同平台上的工作原理。您将了解什么是栈和堆,如何避免内存泄漏,以及为什么 WeakReference 可以拯救您的项目。我们开始吧!

\n\n

Kotlin 中的内存是什么?栈、堆及其伙伴

\n\n

Kotlin 是一种多平台语言。它可以编译为 JVM 字节码、原生代码(通过 Kotlin/Native)或 JavaScript(Kotlin/JS)。在每个平台上,内存的组织方式略有不同,但基础是相同的。

\n\n

让我们回顾一下基础知识。当您的程序启动时,操作系统会为其分配一块内存区域。在这个区域内,有两个主要的“区域”:

\n\n
    \n
  • 栈 (Stack) — 这里存储局部变量、基本类型和对象引用。它像一叠盘子一样工作:快速、可预测,但大小有限。超出栈限制会导致 StackOverflowError。
  • \n
  • 堆 (Heap) — 所有通过 new 或构造函数(val list = mutableListOf())创建的对象都存放在这里。堆很大,但速度较慢,并且 Kotlin 垃圾回收器 正是在这里“工作”。
  • \n
\n\n

在 JVM 上,栈和堆以经典方式工作。在 Kotlin/Native 中,栈是线程的原生栈,而堆由其自身的垃圾回收器管理。在 Kotlin/JS 中,一切都由 JavaScript 引擎(V8、SpiderMonkey)负责。

\n\n

关键点是:对象引用存储在栈中,而对象本身存储在堆中。只要对象至少有一个“活动”引用(来自栈或其他对象),垃圾回收器就不会碰它。

\n\n

Kotlin 中的垃圾回收器:它在 JVM 上如何工作

\n\n

当您在 JVM(Android、服务器)上编写 Kotlin 代码时,您将获得 Java 虚拟机垃圾回收器 (GC) 的强大功能。这不是 Kotlin 特有的,但理解其机制是必要的。

\n\n

现代 JVM 使用 G1GC (Garbage First) 或 ZGC(在新版本中)。简化的工作方式如下:

\n\n
    \n
  1. 标记 (Mark) — GC 从根节点(栈、静态字段)开始,“遍历”所有活动对象。所有它能到达的对象都是活动的。
  2. \n
  3. 清除 (Sweep) — 所有未标记的对象都被视为垃圾并被删除。
  4. \n
  5. 压缩 (Compact) — 活动对象被移动,以避免碎片化。
  6. \n
\n\n

在 G1GC 中,堆被划分为多个区域。GC 会收集那些垃圾最多的区域(因此得名)。这减少了暂停时间,但并未完全消除它们。

\n\n

在 Kotlin 中,您可以通过 JVM 标志(对于服务器)或通过 GarbageCollectorMXBean(用于监控)来影响垃圾回收器。但大多数情况下,您只需要编写不妨碍 GC 工作的代码。

\n\n

示例:GC 如何看待您的代码

\n\n
fun processData() {\n    val list = mutableListOf<String>()\n    for (i in 1..100_000) {\n        list.add("Element $i")\n    }\n    // 这里 list 是活动的,直到方法结束\n    println(list.size)\n    // 方法退出后,list 变成垃圾\n}\n
\n\n

在 processData() 完成后,对 list 的引用从栈中消失,该对象成为垃圾回收的候选对象。很简单,对吧?

\n\n

Kotlin/Native 的特性:没有 JVM 的垃圾回收器

\n\n

Ko

博客

书籍推荐