Skip to content

内存模型演进

源:Memory Management Evolution - Kotlin/Native

Kotlin/Native 的内存模型经历了从严格线程隔离到现代 GC 的重大演进。理解这段历史有助于迁移遗留代码。

传统内存模型 (Legacy MM)已废弃

###设计理念

传统模型基于 严格的线程隔离对象冻结

kotlin
// 传统模型的核心概念
class DataHolder(var value: Int)

fun legacyThreading() {
    val data = DataHolder(42)
    
    // 在主线程修改
    data.value = 100  // ✅ OK
    
    // 跨线程共享前必须冻结
    data.freeze()
    
    // ❌ 冻结后无法修改
    // data.value = 200  // InvalidMutabilityException
    
    // Worker 线程
    Worker.start().execute(TransferMode.SAFE, { data }) {
        // 只能读取冻结的对象
        println(it.value)  // OK: 100
    }
}

freeze() 机制

kotlin
@OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*

class MutableState {
    var counter = 0
    val list = mutableListOf<String>()
}

fun demonstrateFreeze() {
    val state = MutableState()
    
    // 冻结前
    state.counter++  // ✅ 可修改
    state.list.add("item")  // ✅ 可修改
    
    // 冻结
    state.freeze()
    
    // 冻结后
    println(state.isFrozen)  // true
    println(state.counter)  // ✅ 可读取
    
    // state.counter++  // ❌ InvalidMutabilityException
    // state.list.add("item2")  // ❌ InvalidMutabilityException
}

TransferMode

kotlin
@OptIn(ObsoleteWorkersApi::class)
enum class TransferMode {
    // 安全模式:自动冻结对象
    SAFE,
    
    // 不安全模式:不执行检查(开发者自己保证安全)
    UNSAFE
}

fun useTransferMode() {
    val data = DataHolder(42)
    
    // SAFE:Worker.execute 自动冻结 data
    Worker.start().execute(TransferMode.SAFE, { data }) {
        // it 是冻结的
        println(it.isFrozen)  // true
    }
}

传统模型的问题

主要局限性

  1. 学习曲线陡峭 - 开发者需要掌握冻结机制
  2. 共享困难 - 可变对象无法跨线程共享
  3. 性能开销 - 频繁的对象拷贝
  4. 内存泄漏 - 循环引用引起泄漏
  5. 与 JVM 差异大 - 跨平台代码难以维护
kotlin
// ❌ 传统模型的痛点
class LegacyPainPoint {
    fun complexSharing() {
        val data = mutableMapOf<String, MutableList<Int>>()
        
        data["key"] = mutableListOf(1, 2, 3)
        
        // 要跨线程共享需要:
        // 1. 冻结整个对象图
        data.freeze()
        
        // 2. 无法再修改
        // data["key"]?.add(4)  // 错误!
        
        // 3. 如果需要修改,必须拷贝
        val workerData = data.toMutableMap()  // 深拷贝
        // 性能开销大
    }
}

新内存模型 (New MM)Kotlin 1.7.20+

核心特性

新模型带来了现代垃圾回收

kotlin
// 新模型:自由共享
class ModernThreading {
    fun simpleSharing() {
        val counter = AtomicInt(0)
        val list = mutableListOf<String>()
        
        // ✅ 直接跨线程共享,无需冻结
        repeat(10) {
            Thread {
                counter.incrementAndGet()
                synchronized(list) {
                    list.add("Item $it")
                }
            }.start()
        }
        
        Thread.sleep(100)
        println("Counter: ${counter.value}")
        println("List size: ${list.size}")
    }
}

GC 算法

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

fun exploreNewGC() {
    // 新 GC 是并发标记-清除收集器
    
    // 手动触发 GC
    GC.collect()
    
    // 安排 GC(非阻塞)
    GC.schedule()
    
    // 获取 GC 信息
    val info = GC.lastGCInfo
    if (info != null) {
        println("GC pause: ${info.pauseTimeNs / 1_000_000.0}ms")
        println("Memory freed: ${info.freedBytes / 1024}KB")
        println("Objects freed: ${info.freedObjectsCount}")
    }
}

对象共享

kotlin
@OptIn(FreezingIsDeprecated::class)
// ❌ 传统:需要冻结
class LegacyCache {
    private val cache = mutableMapOf<String, String>()
    
    init {
        freeze()  // 整个对象冻结
    }
    
    fun get(key: String): String? {
        return cache[key]  // 只能读
    }
    
    // 无法实现 put,因为对象已冻结
}
kotlin
// ✅ 新模型:直接共享 + 同步
class ModernCache {
    private val cache = mutableMapOf<String, String>()
    private val lock = Any()
    
    fun get(key: String): String? {
        return synchronized(lock) {
            cache[key]
        }
    }
    
    fun put(key: String, value: String) {
        synchronized(lock) {
            cache[key] = value
        }
    }
}

迁移指南

检查 Kotlin 版本

kotlin
// build.gradle.kts

// ✅ 新内存模型:1.7.20+
kotlin("multiplatform") version "1.9.20"

// ❌ 旧版本需升级
// kotlin("multiplatform") version "1.6.21"

移除 freeze 调用

kotlin
@OptIn(FreezingIsDeprecated::class)
class Before {
    private val data = MyData()
    
    init {
        data.freeze()  // ❌ 删除这行
    }
    
    fun share(): MyData {
        return data.freeze()  // ❌ 删除 freeze()
    }
}
kotlin
// ✅ 直接共享,添加必要的同步
class After {
    @Volatile
    private var data = MyData()
    
    fun share(): MyData {
        return data
    }
    
    fun update(newData: MyData) {
        data = newData  // @Volatile 保证可见性
    }
}

替换 Worker API

kotlin
@OptIn(ObsoleteWorkersApi::class)
import kotlin.native.concurrent.Worker

// ❌ 旧 API
fun oldWay() {
    val worker = Worker.start()
    
    val future = worker.execute(TransferMode.SAFE, { input }) {
        processData(it)
    }
    
    val result = future.result
    worker.requestTermination().result
}
kotlin
import kotlinx.coroutines.*

// ✅ 新方式:使用协程
suspend fun newWay() = withContext(Dispatchers.Default) {
    val result = async {
        processData(input)
    }
    
    result.await()
}

更新依赖

kotlin
// build.gradle.kts
dependencies {
    // ❌ 旧版本(native-mt 后缀)
    // implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt")
    
    // ✅ 新版本(无后缀)
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}

移除注解

kotlin
// ❌ 删除这些注解
@SharedImmutable  // 不再需要
val globalData = listOf(1, 2, 3)

@ThreadLocal  // 根据实际需求保留或删除
var threadData = 0

修改全局初始化

kotlin
// 传统模型:全局变量立即初始化
val heavyObject = ExpensiveComputation()  // 启动时执行

// 新模型:默认延迟初始化
val heavyObject = ExpensiveComputation()  // 首次访问时执行

// 如需立即初始化
@EagerInitialization
val eagerObject = ExpensiveComputation()  // 启动时执行

性能对比

对象创建

操作Legacy MMNew MM提升
简单对象创建100ns80ns1.25x
跨线程传递300ns (冻结+拷贝)50ns (直接共享)6x
大对象共享 (1MB)5ms (深拷贝)0.1ms (引用)50x

GC 暂停时间

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

并发性能

kotlin
// 性能测试:1000 次并发写入
@OptIn(ExperimentalTime::class)
import kotlin.time.measureTime

fun benchmarkConcurrency() {
    val threads = 10
    val iterations = 100
    
    val duration = measureTime {
        val counter = AtomicInt(0)
        
        List(threads) {
            Thread {
                repeat(iterations) {
                    counter.incrementAndGet()
                }
            }
        }.forEach { it.start(); it.join() }
    }
    
    println("Completed in: ${duration.inWholeMilliseconds}ms")
    // Legacy MM: ~500ms (因为冻结/拷贝)
    // New MM: ~50ms (直接共享)
}

最佳实践

实践:使用原子类型

kotlin
import kotlinx.atomicfu.*

// ✅ 线程安全的计数器
class SafeCounter {
    private val _count = atomic(0)
    
    val count: Int
        get() = _count.value
    
    fun increment() {
        _count.incrementAndGet()
    }
}

实践:合理使用同步

kotlin
// ✅ 细粒度锁
class OptimizedCache {
    private val cache = ConcurrentHashMap<String, String>()
    
    fun get(key: String) = cache[key]
    fun put(key: String, value: String) = cache.put(key, value)
}

// ✅ 读写锁
class RWLockCache {
    private val cache = mutableMapOf<String, String>()
    private val lock = ReentrantReadWriteLock()
    
    fun get(key: String): String? {
        lock.read {
            return cache[key]
        }
    }
    
    fun put(key: String, value: String) {
        lock.write {
            cache[key] = value
        }
    }
}

新内存模型极大简化了 Kotlin/Native 的并发编程。迁移工作量相对较小,但收益显著。建议所有新项目直接使用新模型,旧项目尽快迁移。