Skip to content

内存模型演进

源:Kotlin/Native Memory Model Evolution

Kotlin/Native 的内存模型经历了重大演进,从严格的对象不可变模型转向更现代的自动内存管理。了解这段历史有助于理解当前设计。

传统内存模型 (Legacy MM)

不可变性与冻结

传统模型基于严格的线程隔离

kotlin
// 传统模型
class Counter {
    var value = 0
    
    fun increment() {
        value++
    }
}

fun oldThreading() {
    val counter = Counter()
    counter.increment()  // OK: 在主线程
    
    // 跨线程共享前必须冻结
    counter.freeze()
    
    Worker.start().execute(TransferMode.SAFE, { counter }) {
        // ❌ InvalidMutabilityException
        // it.increment()  // 冻结后无法修改
        
        // ✅ 只能读取
        println(it.value)
    }
}

Worker 线程模型

kotlin
// 传统 Worker API
val worker = Worker.start()

// 传递数据到 Worker
val future = worker.execute(TransferMode.SAFE, { "Data" }) { data ->
    // Worker 线程中执行
    processData(data)
}

// 获取结果
val result = future.result

// 清理
worker.requestTermination().result

局限性

  1. 开发复杂度高 - 需要手动管理冻结
  2. 共享困难 - 可变对象无法跨线程共享
  3. 性能开销 - 频繁的对象拷贝
  4. 与 JVM 差异大 - 难以编写跨平台代码

新内存模型 (New MM)

自动内存管理

新模型(Kotlin 1.7.20 起默认)移除了冻结限制:

kotlin
// 新模型
class Counter {
    @Volatile
    var value = 0
    
    fun increment() {
        atomicValue.incrementAndGet()
    }
}

fun newThreading() {
    val counter = Counter()
    
    // ✅ 直接跨线程共享,无需冻结
    repeat(5) {
        Worker.start().execute(TransferMode.SAFE, { counter }) {
            it.increment()
        }
    }
    
    // 需要手动同步
    Thread.sleep(100)
    println(counter.value)  // 5
}

GC 改进

kotlin
@OptIn(ExperimentalStdlibApi::class)
import kotlin.native.runtime.GC

// 新 GC 控制
GC.collect()  // 触发 GC
GC.schedule()  // 安排 GC

// 获取 GC 信息
val info = GC.lastGCInfo
println("GC pause: ${info?.pauseTimeNs}ns")

迁移指南

迁移步骤

kotlin
class DataProcessor {
    private val cache = mutableMapOf<String, String>()
    
    init {
        freeze()  // 冻结整个对象
    }
    
    fun process(key: String): String? {
        // ❌ 无法修改 cache
        return cache[key]
    }
}
kotlin
class DataProcessor {
    // ✅ 使用线程安全的集合
    private val cache = ConcurrentMutableMap<String, String>()
    
    // 或使用锁
    private val lock = Any()
    private val cacheWithLock = mutableMapOf<String, String>()
    
    fun process(key: String): String? {
        return synchronized(lock) {
            cacheWithLock[key]
        }
    }
}

删除 freeze 调用

bash
# 查找所有 freeze 调用
grep -r "\.freeze()" src/

# 评估是否需要替代方案
# - 不需要跨线程 → 删除
# - 需要线程安全 → 添加同步

使用 @OptIn 标注

kotlin
// 如果必须保留 freeze(临时)
@OptIn(FreezingIsDeprecated::class)
fun legacyCode() {
    val obj = MyObject()
    obj.freeze()
}

性能对比

对象创建

场景Legacy MMNew MM提升
简单对象创建100ns80ns1.25x
跨线程传递300ns (拷贝)50ns (直接)6x
大对象共享5000ns100ns50x

GC 暂停时间

堆大小Legacy STWNew MM改善
10MB5ms2ms2.5x
100MB50ms8ms6.25x
1GB500ms30ms16.7x

新内存模型带来了更符合直觉的编程体验,同时保持了出色的性能。迁移工作量不大,收益显著。