Kotlin/Native
最近 KMP 或者说 KMM 在移动端挺火,我非常好奇它是如何跨端的
看了一下官方文档,只知道是通过 LLVM 把 Kotlin 转为 IR 再转为目标平台二进制。这部分我目前还没去分析,因为 LLVM 相关的知识我实在知之甚少,后面也会去补足
但是,我渐渐发现了另一个点:在我们写 kotlin 代码的时候,我们并不会显式执行内存释放
的操作(比如 c/c++ 会显示调用 free/delete,比如 rust 有 drop trait)。那么,将 kotlin 代码转换为二进制的时候,如何处理这种内存释放的问题?
那我们肯定猜到是有垃圾回收的逻辑的。要么引用计数,要么就是一个现代的垃圾回收器。
如果引用计数,需要在生成代码的时候维护一个引用指针
如果是垃圾回收器,那么不单单需要一个垃圾回收器,还要知道所有的内存分配情况,所以还需要一个 heap 的概念,作为内存的大管家。
Kotlin Native Memory Management
看了 kotlin 官方文档是说,一开始使用引用计数来做内存回收,但是无法处理循环引用,而且似乎线程之间的内存共享也有问题(具体不太清楚,并不是第一批的 KMM 使用者)?总之,最终实现了一个类似 jvm 的垃圾回收器,使用的 cms
那 cms 理论上是存在 stop the world
的,kotlin 官方文档 也提及了类似的问题。抱着去验证文档内容的心态,创建了一个 kmm demo,于是发现了如下的线程:
所以,除了发现有 main gc thread(后续看了下 cms 在 mark 阶段也可能是多线程的) 以外,还有一个 gc timer thread
为了搞清楚 gc timer thread,我去寻找了 kotlin native 的源码
然后被一个命名问题困扰了一天,最后终于发现了问题的原因,也是一个非常搞笑的事情
源码目录
我们可以直接找到 kotlin 工程中的 kotlin native 目录,然后其中很显眼的有个 runtime,显然就是运行时的必要组件,这里当然也包含了 gc 相关的逻辑
于是我们会到 gc 目录下是如下的样子:
惊奇的发现,其实存在多种 gc 方式,这也体现了 kotlin native 其实还在不断完善中,并算不上是一个完美的方案
同时,也找到了我们关注的 gc scheduler。但是很不幸,gc scheduler 也有多种
因为各自方案均有多种,这对于我阅读代码增加了一些困扰。幸运的是,经过一段时间的翻阅,我大概理清了逻辑。我们只需要关注 cms 和 adaptive scheduler 即可
adaptive scheduler 即是我们 gc timer thread(也是现在 kotlin 默认使用的)
逻辑也较为好懂,gc timer thread 每隔固定时间回来判断当前是否需要 gc。
同时,如果发生了内存分配操作,allocator 会通知到 gc scheduler(setAllocationBytes),然后根据 memory boundary 来判定是否要执行 gc。而 gc(cms) 中又有很多细节,包括 barrier, parallel mark 等等,这部分理论知识欠缺,有点没看明白
好奇心害死猫
其实,上面得到的这些论证,已经满足了我的基本好奇心了。无论是 LLVM 还是一个 CMS 算法,对于目前的我来说,都很难看得懂。
但是,我一不小心发现了如下代码,导致自己浪费了一天
无论是 kmm demo 中 debugger 展示的线程名,还是 kotlin 官方文档中的介绍,都是说使用的 cms,为啥到这里变成了这个 parallel_mark_concurrent_sweep?
还记得上面提到的源码目录么,这个东西的目录名字叫做 pmcs,并不是 cms,而且里面的代码就叫做 ParallelMarkConcurrentSweep.cpp,而且翻阅 konan config 发现,还真有 pmcs
于是,彻底懵逼了,难道新版本的 kotlin 使用了 pmcs,kotlin 文档没来得及更新?反查自己的 kotlin 版本 1.9.20,已经非常新了,查阅 1.9.20 分支代码,默认仍然是 pmcs,但是 debugger 确确实实显示的是 cms···
浪费了一天以后发现,目前 pmcs 和 cms 好像是一个东西···对比了一下代码也非常类似
同时,看了一下历史提交,发现了一个非常搞笑的事情
这次提交,将默认的 cms 修改为了 pmcs,但是 native library 用的依然还是 cms.bc
我们再看一下编译的 module
发现 cms.bc 就是对应的 gc/cms/cpp 的代码
所以,现在并不存在所谓的 pmcs 都是 cms,而 cms 的代码 和 pmcs 的代码基本一致
哈哈一笑,浪费了一天
总结
经过查阅 gc 这块内容,发现 kotlin/native 目前并算不上成熟,所以还是继续观望吧