Kotlin: Kotlin性能优化详解
最后更新:2026-08-26
性能不是过早优化——是正确的选择:Charlie 用 替代 链避免百万订单的中间集合分配,用 替代 消除装箱,用 JMH 验证每一步优化的实际收益。
1. 你将学到
- 函数:消除 Lambda 对象分配
- 集合选型: vs vs vs
- 协程调度器调优
- 原生类型数组: vs
- Charlie 实战:百万订单吞吐优化
2. 一个架构师的真实故事
(1) 痛点:百万订单处理内存溢出
Charlie 的 OrderProcessor 处理百万订单时, 每步创建新集合,内存峰值 4GB,GC 暂停 2 秒。
(2) 性能优化的解法
KOTLIN
// Before: 3 intermediate collections, 4GB peak memory
orders.map { enrich(it) }.filter { it.total > 100 }.groupBy { it.region }
// After: 0 intermediate collections, 200MB peak memory
orders.asSequence()
.map { enrich(it) }
.filter { it.total > 100 }
.groupBy { it.region } // Only 1 final collection
Sequence 惰性求值 + 原生类型数组 + 协程池调优 = 内存降低 95%,吞吐提升 10x。
3. inline 函数消除开销
(1) Lambda 的隐藏成本
KOTLIN
// Non-inline: Lambda compiles to anonymous class
fun process(order: Order, block: (Order) -> String): String {
return block(order) // Creates Function1 object every call
}
// Inline: Lambda code is inlined at call site
inline fun process(order: Order, block: (Order) -> String): String {
return block(order) // No object allocation!
}
(2) inline 效果测量
KOTLIN
// JMH micro-benchmark (conceptual)
// Non-inline: ~50ns per call (object allocation)
// Inline: ~5ns per call (no allocation, JIT inlines further)
(3) inline 使用指南
| 场景 | 推荐 | 原因 |
|---|---|---|
| 高阶函数(1-5 行体) | ✅ inline | 消除 Lambda 对象分配 |
| reified 类型参数 | ✅ 必须 inline | 编译期保留类型 |
| 大函数体(>20 行) | ❌ 不 inline | 增加代码体积 |
| Lambda 被存储/传递 | ❌ 不 inline | 内联后 Lambda 不存在了 |
4. 集合选型
(1) 四种数据处理方式
KOTLIN
// 1. List (Eager): each step creates new collection
val result1 = orders
.map { enrich(it) } // New List
.filter { it.total > 100 } // New List
.toList() // New List
// 2. Sequence (Lazy): processes one element at a time
val result2 = orders.asSequence()
.map { enrich(it) }
.filter { it.total > 100 }
.toList() // Only 1 List
// 3. Flow (Async Lazy): suspend-capable lazy stream
val result3 = orders.asFlow()
.map { enrichAsync(it) } // Can be suspend
.filter { it.total > 100 }
.toList() // Only 1 List
// 4. Array: lowest overhead, fixed size
val result4 = ordersArray
.map { enrich(it) } // Creates new Array
.filter { it.total > 100 } // No filter on Array
(2) 集合选型决策树
flowchart LR
A[Data Processing] --> B{Async needed?}
B -->|Yes| C[Flow]
B -->|No| D{Data size?}
D -->|Large >10K| E{Multiple steps?}
D -->|Small <10K| F[List]
E -->|Yes| G[Sequence]
E -->|No| F
A --> H{Primitive types?}
H -->|Yes| I[IntArray/DoubleArray]
H -->|No| A
(3) 性能对比
| 方式 | 内存 | CPU | 适用场景 |
|---|---|---|---|
| O(n×步数) | 低(缓存友好) | 小数据、少步骤 | |
| O(1) | 中(每元素完整流水线) | 大数据、多步骤 | |
| O(1) | 中+异步开销 | 异步数据源 | |
| O(n) | 最低(无装箱) | 基本类型、固定大小 |
5. 原生类型数组
(1) IntArray vs Array
KOTLIN
// Array`<Int>`: each element is boxed Integer object
val boxed: Array`<Int>` = Array(1_000_000) { it }
// Memory: ~24MB (4MB data + 20MB object headers)
// IntArray: primitive int[], no boxing
val primitive: IntArray = IntArray(1_000_000) { it }
// Memory: ~4MB (no object overhead)
// 6x memory savings for primitive arrays!
(2) 原生类型数组选择
| 类型 | 装箱数组 | 原生数组 | 节省 |
|---|---|---|---|
| Int | ~6x | ||
| Long | ~6x | ||
| Double | ~6x | ||
| Boolean | ~8x |
6. 协程调度器调优
(1) 调度器选择
KOTLIN
// Default: CPU-bound (parallelism = CPU cores)
launch(Dispatchers.Default) { sortLargeCollection() }
// IO: blocking I/O (up to 64 threads by default)
launch(Dispatchers.IO) { queryDatabase() }
// Custom: for specific I/O patterns
val orderIoDispatcher = Executors.newFixedThreadPool(32)
.asCoroutineDispatcher()
// Increase IO pool size
System.setProperty("kotlinx.coroutines.io.parallelism", "128")
(2) 调度器调优对比
| 场景 | 默认 | 调优后 | 改善 |
|---|---|---|---|
| 64 并发 DB 查询 | IO 默认 64 线程 | 自定义 128 线程 | 吞吐 2x |
| CPU 密集计算 | Default 4 核 | Fixed 8 线程 | 吞吐 2x |
| 混合负载 | 共享 IO | 隔离线程池 | 延迟降低 50% |
7. JMH 基准测试
(1) JMH 配置
KOTLIN
// build.gradle.kts
dependencies {
implementation("org.openjdk.jmh:jmh-core:1.37")
implementation("org.openjdk.jmh:jmh-generator-annprocess:1.37")
}
(2) 基准测试示例
KOTLIN
@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
open class OrderProcessingBenchmark {
private lateinit var orders: List`<Order>`
@Setup
fun setup() {
orders = (1..100_000).map {
Order("ORD-$it", it * 10.0, "CONFIRMED", "Customer-$it")
}
}
@Benchmark
fun listPipeline(): Map<String, List`<Order>`> {
return orders
.filter { it.total > 1_000 }
.map { it.copy(total = it.total * 0.9) }
.groupBy { it.customer }
}
@Benchmark
fun sequencePipeline(): Map<String, List`<Order>`> {
return orders.asSequence()
.filter { it.total > 1_000 }
.map { it.copy(total = it.total * 0.9) }
.groupBy { it.customer }
}
}
8. 完整示例:百万订单吞吐优化
KOTLIN
// ============================================
// OrderProcessor - Performance Optimization
// Feature: Sequence, IntArray, Coroutines, Benchmarking
// ============================================
import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis
data class Order(val id: String, val total: Double, val status: String, val customer: String)
fun generateOrders(count: Int): List`<Order>` = (1..count).map {
Order("ORD-$it", it * 0.1, if (it % 5 == 0) "CANCELLED" else "CONFIRMED", "CUST-${it % 100}")
}
// Strategy 1: List (eager)
fun processWithList(orders: List`<Order>`): Double {
return orders
.filter { it.status != "CANCELLED" }
.map { it.total }
.sum()
}
// Strategy 2: Sequence (lazy)
fun processWithSequence(orders: List`<Order>`): Double {
return orders.asSequence()
.filter { it.status != "CANCELLED" }
.map { it.total }
.sum()
}
// Strategy 3: IntArray (primitive, no boxing)
fun processWithIntArray(totals: DoubleArray): Double {
return totals.sum()
}
// Strategy 4: Coroutines (parallel)
suspend fun processWithCoroutines(orders: List`<Order>`, chunkSize: Int = 10_000): Double {
return coroutineScope {
orders.chunked(chunkSize)
.map { chunk -> async(Dispatchers.Default) { chunk.filter { it.status != "CANCELLED" }.sumOf { it.total } } }
.awaitAll()
.sum()
}
}
fun main() = runBlocking {
val orderCount = 1_000_000
println("Generating $orderCount orders...")
val orders = generateOrders(orderCount)
val totalsArray = DoubleArray(orderCount) { orders[it].total }
println("\n=== Performance Benchmark ===\n")
// List
val listTime = measureTimeMillis { val r = processWithList(orders); println("List result: \$$r USD") }
println("List time: ${listTime}ms\n")
// Sequence
val seqTime = measureTimeMillis { val r = processWithSequence(orders); println("Sequence result: \$$r USD") }
println("Sequence time: ${seqTime}ms\n")
// IntArray
val arrayTime = measureTimeMillis { val r = processWithIntArray(totalsArray); println("DoubleArray result: \$$r USD") }
println("DoubleArray time: ${arrayTime}ms\n")
// Coroutines
val coroTime = measureTimeMillis { val r = processWithCoroutines(orders); println("Coroutine result: \$$r USD") }
println("Coroutine time: ${coroTime}ms\n")
// Summary
println("=== Optimization Summary ===")
println(" List vs Sequence speedup: ${"%.1f".format(listTime.toDouble() / seqTime)}x")
println(" List vs DoubleArray speedup: ${"%.1f".format(listTime.toDouble() / arrayTime)}x")
println(" List vs Coroutine speedup: ${"%.1f".format(listTime.toDouble() / coroTime)}x")
}
输出(示例,实际取决于硬件):
TEXT
📖 仅展示
Generating 1000000 orders...
=== Performance Benchmark ===
List result: $4.99995E7 USD
List time: 120ms
Sequence result: $4.99995E7 USD
Sequence time: 45ms
DoubleArray result: $5.0E7 USD
DoubleArray time: 3ms
Coroutine result: $4.99995E7 USD
Coroutine time: 35ms
=== Optimization Summary ===
List vs Sequence speedup: 2.7x
List vs DoubleArray speedup: 40.0x
List vs Coroutine speedup: 3.4x
❓ 常见问题
Q 什么时候应该优化性能?
A 先写正确的代码,再测量瓶颈,最后针对性优化。过早优化是万恶之源——但选择正确的数据结构(Sequence vs List)不算过早优化,是设计决策。
Q inline 会让包体积变大吗?
A 会。每次内联都会在调用处插入代码副本。高频调用的小函数内联收益大,大函数内联会导致包膨胀。标准库已做好平衡。
Q Sequence 一定比 List 快吗?
A 不一定。小数据量(<1000)和单步操作中 List 可能更快(缓存友好、无 Sequence 包装开销)。3+ 步操作 + 大数据量时 Sequence 才有优势。
Q IntArray 和 List 哪个更快?
A IntArray 避免装箱和对象分配,遍历和求和快 5-10x。但 IntArray 不支持函数式操作符(map/filter),需要手动循环或转换。
Q 协程就一定比线程快吗?
A 不是。CPU 密集型任务协程和线程性能相当。协程的优势在 I/O 密集型场景——用少量线程处理大量并发 I/O,避免线程阻塞开销。
Q 如何正确测量 Kotlin 性能?
A 用 JMH(Java Microbenchmark Harness)。不要用 做微基准测试——JIT 编译、GC、类加载都会干扰结果。JMH 自动处理这些。
📖 小节
- 消除 Lambda 对象分配,但大函数内联会增加代码体积
- 惰性求值避免中间集合,大数据 + 多步操作首选
- / 避免装箱,数值计算快 5-10x
- 协程调度器调优:IO 密集用 ,CPU 密集用
- JMH 是微基准测试的标准工具,避免手动测量
- 优化步骤:正确 → 测量 → 优化 → 再测量
📝 作业
- 基础题(难度⭐):用 对比 和 在 100,000 个元素上的执行时间。提示:
- 进阶题(难度⭐⭐):用 实现订单总金额计算,对比
<Double>的性能。提示: - 挑战题(难度⭐⭐⭐):用 JMH 编写正式基准测试,对比 List/Sequence/Flow 三种方式处理 100 万订单的吞吐量。提示: +