Kotlin: Kotlin性能优化详解

最后更新:2026-08-26

性能不是过早优化——是正确的选择:Charlie 用 替代 链避免百万订单的中间集合分配,用 替代 消除装箱,用 JMH 验证每一步优化的实际收益。

1. 你将学到


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) 集合选型决策树

100%
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 自动处理这些。

📖 小节


📝 作业

  1. 基础题(难度⭐):用 对比 和 在 100,000 个元素上的执行时间。提示:
  2. 进阶题(难度⭐⭐):用 实现订单总金额计算,对比 <Double> 的性能。提示:
  3. 挑战题(难度⭐⭐⭐):用 JMH 编写正式基准测试,对比 List/Sequence/Flow 三种方式处理 100 万订单的吞吐量。提示: +

← 上一课 | 下一课 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏