对象冻结机制已废弃 - Kotlin 1.9.20 完全移除
源:Kotlin/Native Memory Manager
对象冻结是传统内存模型的核心机制,用于实现线程安全的对象共享。虽然已被新内存模型取代,但理解其设计有助于维护遗留代码和理解 Kotlin/Native 的演进历程。
冻结机制设计
为什么需要冻结
传统 Kotlin/Native 采用严格的线程隔离模型:
每个线程拥有独立的对象堆
↓
可变对象只能被单个线程访问
↓
跨线程共享必须保证不可变性
↓
通过 freeze() 实现对象不可变这种设计避免了数据竞争,但增加了编程复杂度[来源:Touchlab KN Concurrency Guide]。
freeze() 方法
kotlin
@OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
class MutableState(var value: Int)
fun basicFreeze() {
val data = MutableState(42)
// 冻结前:完全可变
data.value = 100 // ✅ OK
println(data.isFrozen) // false
// 执行冻结
data.freeze()
// 冻结后:完全不可变
println(data.isFrozen) // true
println(data.value) // ✅ 100 (只能读取)
// ❌ 任何修改都会抛出 InvalidMutabilityException
try {
data.value = 200
} catch (e: InvalidMutabilityException) {
println("Cannot modify frozen object: ${e.message}")
}
}核心特性:
- 不可逆:一旦冻结,永远无法解冻
- 递归:冻结会传播到整个对象图
- 线程安全:冻结对象可在所有线程间安全共享
冻结传播
深度冻结
冻结操作会递归遍历整个对象图,冻结所有可达对象:
kotlin
@OptIn(FreezingIsDeprecated::class)
class Node(val value: Int, var next: Node? = null)
fun freezePropagation() {
// 创建链表 1 → 2 → 3
val node1 = Node(1)
val node2 = Node(2)
val node3 = Node(3)
node1.next = node2
node2.next = node3
// 仅冻结 node1
node1.freeze()
// 验证传播:整个链表都被冻结
println("node1.isFrozen: ${node1.isFrozen}") // true
println("node2.isFrozen: ${node2.isFrozen}") // true ← 自动传播
println("node3.isFrozen: ${node3.isFrozen}") // true ← 自动传播
// ❌ 无法修改链表中的任何节点
// node2.next = null // InvalidMutabilityException
// node3.value = 99 // val 本身不可变,但如果是 var 会抛异常
}复杂对象图
kotlin
@OptIn(FreezingIsDeprecated::class)
data class Person(
val name: String,
var age: Int,
val friends: MutableList<Person> = mutableListOf()
)
fun complexGraphFreeze() {
val alice = Person("Alice", 30)
val bob = Person("Bob", 25)
val charlie = Person("Charlie", 35)
// 构建好友关系
alice.friends.add(bob)
alice.friends.add(charlie)
bob.friends.add(alice)
// 冻结 Alice
alice.freeze()
// 验证:所有人和列表都被冻结
println("alice.isFrozen: ${alice.isFrozen}") // true
println("bob.isFrozen: ${bob.isFrozen}") // true ← 通过 friends 传播
println("charlie.isFrozen: ${charlie.isFrozen}") // true ← 通过 friends 传播
println("alice.friends.isFrozen: ${alice.friends.isFrozen}") // true
// ❌ 所有修改操作都失败
// alice.age = 31 // InvalidMutabilityException
// bob.age = 26 // InvalidMutabilityException
// alice.friends.add(Person("Dave", 28)) // InvalidMutabilityException
}Worker 线程模型集成
TransferMode.SAFE
Worker API 与冻结机制紧密集成:
kotlin
@OptIn(ObsoleteWorkersApi::class, FreezingIsDeprecated::class)
import kotlin.native.concurrent.Worker
fun workerAutoFreeze() {
val worker = Worker.start()
val data = MutableList(5) { it * 10 }
println("Before transfer: ${data.isFrozen}") // false
// SAFE 模式:自动冻结传递的对象
val future = worker.execute(TransferMode.SAFE, { data }) { input ->
println("In worker: ${input.isFrozen}") // true ← 自动冻结
// ❌ 无法修改
// input[0] = 999 // InvalidMutabilityException
input.sum() // 只能读取
}
val result = future.result
println("Result: $result") // 100
// 原对象也被冻结了
println("After transfer: ${data.isFrozen}") // true
worker.requestTermination().result
}TransferMode.UNSAFE
kotlin
@OptIn(ObsoleteWorkersApi::class, FreezingIsDeprecated::class)
fun workerUnsafeMode() {
val worker = Worker.start()
val data = mutableListOf(1, 2, 3)
// 手动冻结
data.freeze()
// UNSAFE 模式:跳过检查(危险!)
worker.execute(TransferMode.UNSAFE, { data }) { input ->
println("Received: $input")
input.sum()
}.result
worker.requestTermination().result
}检查与验证
isFrozen 属性
所有对象都有 isFrozen 属性:
kotlin
@OptIn(FreezingIsDeprecated::class)
fun checkFrozenStatus() {
val list = mutableListOf(1, 2, 3)
val map = mutableMapOf("key" to "value")
// 动态检查
if (!list.isFrozen) {
list.add(4) // 安全:未冻结可以修改
}
list.freeze()
if (list.isFrozen) {
// 只能读取
println("List size: ${list.size}")
val copy = list.toList() // 创建可变副本
}
}ensureNeverFrozen()
标记对象永远不应被冻结:
kotlin
@OptIn(FreezingIsDeprecated::class)
class MustRemainMutable {
var counter = 0
init {
// 确保此对象永远不会被冻结
ensureNeverFrozen()
}
fun increment() {
counter++
}
}
fun tryFreezeProtected() {
val obj = MustRemainMutable()
obj.increment() // ✅ OK
try {
obj.freeze()
println("Freeze succeeded (unexpected)")
} catch (e: IncorrectDereferenceException) {
println("❌ Freeze failed as expected: ${e.message}")
// 错误:对象被 ensureNeverFrozen() 保护
}
}常见问题与解决方案
问题1:意外冻结大量对象
kotlin
@OptIn(FreezingIsDeprecated::class)
// ❌ 问题代码
class AppConfig {
val database = DatabaseConnection()
val cache = mutableMapOf<String, Any>()
var debugMode = false
}
fun problemCode() {
val config = AppConfig()
// 传递给 Worker 时会冻结整个 config
// 包括 database 和 cache
config.freeze()
// ❌ 后续无法修改 cache 或 debugMode
}解决方案:使用 @SharedImmutable 或分离可变部分
kotlin
@OptIn(FreezingIsDeprecated::class)
// ✅ 改进:分离可变和不可变部分
@SharedImmutable
val sharedConfig = object {
val databaseUrl = "jdbc:..."
val apiEndpoint = "https://api.example.com"
}
// 可变部分保持在线程本地
class MutableAppState {
var debugMode = false
val cache = mutableMapOf<String, Any>()
}问题2:InvalidMutabilityException 调试
kotlin
@OptIn(FreezingIsDeprecated::class)
fun debugFreeze() {
val data = mutableListOf("a", "b", "c")
// 在关键位置检查
println("Before operation: isFrozen=${data.isFrozen}")
someOperation(data)
println("After operation: isFrozen=${data.isFrozen}")
if (data.isFrozen) {
println("⚠️ Data was frozen by someOperation")
// 追踪哪里冻结的
}
}迁移到新内存模型
移除 freeze 调用
kotlin
@OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
class DataProcessor {
fun processInBackground(data: List<Int>) {
val worker = Worker.start()
// 旧模型:必须冻结
data.freeze()
worker.execute(TransferMode.SAFE, { data }) {
it.sum()
}
worker.requestTermination()
}
}kotlin
import kotlinx.coroutines.*
// ✅ 新模型:无需冻结
class DataProcessor {
suspend fun processInBackground(data: List<Int>) = withContext(Dispatchers.Default) {
data.sum() // 直接使用,无需冻结
}
}替换 @SharedImmutable
kotlin
// Legacy
@OptIn(FreezingIsDeprecated::class)
@SharedImmutable
val globalConstants = mapOf(
"API_KEY" to "...",
"VERSION" to "1.0"
)
// ✅ New MM:直接定义全局变量
val globalConstants = mapOf(
"API_KEY" to "...",
"VERSION" to "1.0"
)
// 新模型:全局变量自动可跨线程访问,无需标注移除 ensureNeverFrozen
kotlin
// Legacy
@OptIn(FreezingIsDeprecated::class)
class MutableCache {
init {
ensureNeverFrozen() // ❌ 删除
}
var data = mutableMapOf<String, String>()
}
// ✅ New MM:添加必要的同步
class MutableCache {
private val data = mutableMapOf<String, String>()
private val lock = Any()
fun get(key: String): String? = synchronized(lock) {
data[key]
}
fun put(key: String, value: String) = synchronized(lock) {
data[key] = value
}
}性能影响
冻结开销
kotlin
@OptIn(FreezingIsDeprecated::class, ExperimentalTime::class)
import kotlin.time.measureTime
fun freezePerformance() {
// 大对象图
val root = Node(0)
var current = root
repeat(10_000) {
val next = Node(it + 1)
current.next = next
current = next
}
// 测量冻结时间
val duration = measureTime {
root.freeze()
}
println("Freezing 10K nodes took: ${duration.inWholeMilliseconds}ms")
// 典型结果:5-15ms(取决于硬件)
}对象冻结机制在新内存模型中已完全移除。迁移时只需删除 freeze() 调用和相关注解,并根据需要添加适当的同步机制(如 synchronized、AtomicInt 等)。新模型大幅简化了并发编程,性能也有显著提升。