原文地址:blog.jetbrains.com/kotlin/2020…
原文作者:blog.jetbrains.com/author/eliz…
发布时间:2020年7月20日
TL;DR:当前Kotlin/Native中的自动内存管理实现在并发性方面有一定的局限性,我们正在研究替代方案。现有的代码将继续工作,并将得到支持。请继续阅读完整的故事。
一段历史
Kotlin/Native被设计为Kotlin与本地平台特定环境平滑集成的解决方案。从本质上讲,它的愿景是成为C兼容语言,就像Kotlin/JVM之于JVM语言一样--一种实用、简洁、安全、工具友好的代码编写语言。这个故事的一个非常重要的部分是苹果各种平台上的Objective-C框架生态系统。Kotlin/Native对Objective-C生态系统的支持使得在移动应用之间高效地共享Kotlin代码成为可能,并能够自然而精确地使用所有厂商的API,这在基于JVM的解决方案中是很难或无法实现的。
当Kotlin/Native项目在2016年启动时,有必要设计一个内存管理方案。由于Objective-C的互操作性摆在桌面上,我们对那里的自动化内存管理工作方式--使用引用计数--进行了大量的思考和关注。我们甚至试验了一种完全模仿该模型的方法,这将提供提供最无缝的配合的好处。然而,在Objective-C生态系统中,带有循环的对象图并不是由运行时自动管理的。程序员必须识别循环引用,并在源代码中以一种特殊的方式标记它们。在玩弄了这种方法之后,我们很快就得出结论,它与Kotlin的核心理念--让开发更愉快--产生了强烈的冲突。Kotlin确实要求开发者在为了安全而需要这种精确性的地方更加明确,但在这些额外的代码只是可以由语言管理的样本模板的地方就不需要了。不过,引用计数内存管理器的编写还是很容易让Kotlin/Native项目开始的,并且加入了一个基于试删算法的循环垃圾收集器,以提供Kotlin程序员所期望的开发体验。
随着Kotlin/Native项目的成熟和广泛采用,这种基于引用计数的自动化内存管理方案的局限性开始变得更加明显。首先,对于内存分配密集型的应用,很难获得高吞吐量。但是,虽然性能很重要,但它并不是Kotlin设计的唯一因素。
不过,当你把多线程和并发扔进去的时候,局限性就会变得更严重。在所有成功使用全自动引用计数内存管理的生态系统中(最值得注意的是在Python中),并发性通过类似于 "全局解释器锁 "机制的东西受到了严格的限制。对于Kotlin来说,这种方法不是一种选择。对于移动应用来说,能够将CPU密集型操作卸载到与主线程并行运行的后台线程中是非常必要的。
目前的方法是
为了解决这个问题,我们为Kotlin/Native开发了一套独特的限制条件,既能使其高效运行单线程代码,又能使线程之间共享数据成为可能。增加了这样的要求:对象图必须首先被冻结,以防止其被修改。只有这样才能与其他线程共享。另外,如果原线程中没有保留对它的引用,它可以作为一个分离的对象图完全转移到另一个线程中。作为一种奖励,通过只共享不可变的数据,在大多数情况下避免了 "共享可变状态 "的可怕问题。这个方案在一段时间内效果不错。
虽然在概念上很吸引人,但目前Kotlin/Native中的内存管理方法有一些缺陷,阻碍了Kotlin/Native的广泛采用。移动开发者习惯于能够在线程之间自由地共享他们的对象,而且他们已经开发出了一些方法和架构模式来避免在这样做的同时出现数据竞赛。使用Kotlin/Native可以写出不阻塞主线程的高效应用程序,许多早期采用者已经证明了这一点,但这样做的能力伴随着一条陡峭的学习曲线。
Kotlin还有一个方面--目标是能够在不同平台之间共享Kotlin代码。然而,有些并发代码,即使一开始是安全无竞赛的,也几乎不可能在Kotlin/JVM和Kotlin/Native之间共享。特别是,各种并发数据结构和同步基元,既可以是通用的,也可以是特定领域的,结果却在两者之间难以共享,这是众所周知的。
当我们试图为Kotlin/Native实现多线程kotlinx.coroutines时,我们遇到了特别的挑战。同步基元必须在内部共享可突变的状态,这在Kotlin/Native中是通过特殊的原子引用来支持的。然而现有的内存管理算法并没有通过这种引用来跟踪循环。即使经过大量的工作,在某些并发执行场景下,它仍然存在内存泄漏的问题,而我们并没有明确的解决方案来解决这些问题。
新的Kotlin/Native内存管理器
为了解决这些问题,我们已经开始为Kotlin/Native开发一个替代的内存管理器,它将允许我们解除对Kotlin/Native中对象共享的限制,自动跟踪和回收所有未使用的Kotlin内存,提高性能,并提供完全无泄漏的并发编程基元,这些基元是安全的,不需要开发人员的任何特殊管理或注释。新的内存管理器将用于整个编译后的二进制文件。我们计划以一种与现有代码大部分兼容的方式引入它,因此目前正在工作的代码将继续工作。也就是说,我们计划继续支持对象冻结作为无竞赛数据共享的安全机制,我们将研究如何改进Kotlin在整个Kotlin语言中处理不可变数据的方法,而不仅仅是在Kotlin/Native中。现有的与内存管理相关的注释将与新的内存管理器有一个适当的行为,以确保旧的代码仍然有效。同时,我们将继续支持现有的内存管理器,我们将发布Kotlin/Native的多线程库,这样你就可以在它们之上开发你的应用程序。
随着项目的发展和各种设计决定的最终确定,我们将在未来分享更多细节。敬请关注,并享受Kotlin带来的乐趣。
通过( www.DeepL.com/Translator )(免费版)翻译