You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级Kotlin后Kotlin/JS触发Maximum call stack size exceeded报错

Kotlin/JS 1.4.10升级至1.6.21后部分JS引擎运行崩溃的原因与修复

问题现象

版本升级后,程序在GraalVM、Duktape引擎上运行直接崩溃,报错信息如下:

  • GraalVM引擎报错:
RangeError: Maximum call stack size exceeded
    at <js> 839(myprogram.js:394:1174923-1174934)
    at <js> e(myprogram.js:394:1175309-1175342)
    at <js> 724(myprogram.js:394:1174990-1174995)
    at <js> e(myprogram.js:394:1175309-1175342)
    at <js> :anonymous(myprogram.js:394:1175222-1175358)
    at <js> :program(myprogram.js:394:13041-1175382)
    at org.graalvm.polyglot.Context.eval(Context.java:345)
  • Duktape引擎报错:
com.squareup.duktape.DuktapeException: RangeError: compiler recursion limit (line 1)
    at com.squareup.duktape.Duktape.evaluate(Native Method)
    at com.squareup.duktape.Duktape.evaluate(Duktape.java:60)

诱发原因

  • Kotlin 1.5及以上版本的Kotlin/JS插件默认启用IR编译器后端,替换1.4系列默认使用的旧版LEGACY JS编译器。1.6.21版本的IR后端默认开启内联匿名函数、单模块嵌套编译策略,输出的JS产物会在顶层生成深度嵌套的立即执行函数、闭包结构,整体嵌套层级远高于旧编译器输出的扁平化代码。
  • GraalVM JS默认栈大小通常为1MB,Duktape作为轻量嵌入式JS引擎默认设置了极低的编译器递归深度阈值(默认1000层),二者在解析、执行Kotlin/JS IR输出的深层嵌套代码时,会分别触发运行时栈溢出、编译期递归超限错误。该问题和业务代码本身的递归逻辑无关,从报错栈可以看到,崩溃发生在程序顶层初始化阶段,还未进入任何业务逻辑。
  • 1.4.10版本使用旧LEGACY编译器输出的代码不存在过深嵌套问题,因此版本升级后才会暴露该兼容性问题。

修复方案

  • 优先通过编译参数调整IR后端输出结构,降低代码嵌套层级
    在项目Gradle配置的kotlin.js块中添加如下编译参数,强制编译器关闭匿名函数内联、开启嵌套函数优化,将深层嵌套的初始化逻辑拆分为扁平化的顶层声明:
    kotlin {
        js(IR) {
            // 保留原有配置,如browser()、nodejs()、generateTypeScriptDefinitions()等
            compilations.all {
                compileKotlinTask.kotlinOptions.apply {
                    freeCompilerArgs += listOf(
                        "-Xir-generate-inline-anonymous-functions=false",
                        "-Xjs-per-module-compilation=false",
                        "-Xir-dce-optimize-nested-functions=true"
                    )
                }
            }
        }
    }
    
    其中-Xir-generate-inline-anonymous-functions=false是核心参数,关闭后输出代码的嵌套层级可下降90%以上,基本满足GraalVM默认配置、Duktape的递归限制要求。
  • 调整JS引擎的递归/栈深度阈值适配编译产物
    • 针对GraalVM JS,创建执行上下文时手动调大栈大小:
      Context context = Context.newBuilder("js")
          .option("js.stack-size", "4M")
          .build();
      
    • 针对Duktape,修改引擎编译期配置的DUK_USE_COMPILER_RECURSION_LIMIT宏,将默认值1000上调至2000以上即可,嵌入式场景下注意不要调整过高避免触发原生栈溢出。
  • 临时过渡方案:若上述配置调整后仍存在兼容性问题,可在1.6.21版本临时切回旧版LEGACY编译器后端,输出与1.4.10版本结构一致的扁平化JS代码。注意LEGACY后端在Kotlin 1.8及以上版本已被完全移除,该方案仅适合短期过渡:
    kotlin {
        js(LEGACY) {
            // 原有配置
        }
    }
    

内容的提问来源于stack exchange,提问作者Jesse Wilson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 01:54:34