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

Android 4.4.2设备APP运行10分钟出现StackOverflowError崩溃求解决方案

根因判断

从崩溃日志可以直接得出核心结论:StackOverflowError由Collections$SynchronizedCollection.add的无限递归调用导致,栈里连续上百层相同的add调用,说明每次调用add都会触发新的add调用,栈深度持续累加直到超过Android 4.4系统的线程栈上限(默认约1MB,可容纳几百层调用),运行10分钟后触发崩溃。

排查步骤
  • 全局检索代码中所有Collections.synchronizedCollection、Collections.synchronizedSet调用点,检查被包装的集合是否为全局持有、是否被反复执行包装操作:如果将已经经过同步包装的集合对象再次传入同步包装方法,会形成多层包装嵌套,每次add都会穿透多层包装,叠加业务逻辑中的递归调用、AOP切面切入add方法后再次触发add操作,就会形成无限递归。
  • 在HashSet.add处插日志,打印调用栈,可直接定位到触发add操作的自研业务代码(日志里没有自研代码栈是因为栈溢出时栈顶都是系统类调用,完整栈被截断了)。
  • 临时关闭蓝牙扫描逻辑,验证崩溃是否消失,确认是否为蓝牙扫描回调中的逻辑触发的问题。
修复方案
  • 集合的同步包装操作仅在初始化时执行一次,示例如下:
// 正确:仅初始化时做一次同步包装
private final Set<String> bleDataSet = Collections.synchronizedSet(new HashSet<>());

// 错误:每次收到蓝牙数据都重复包装集合,多层包装叠加业务逻辑容易触发栈溢出
public void onBleScanResult(String data) {
    Set<String> tempSet = Collections.synchronizedSet(bleDataSet);
    tempSet.add(data);
}
  • 如果需要保证线程安全,也可以直接使用JDK自带的并发集合CopyOnWriteArraySet、ConcurrentSkipListSet,不需要额外做同步包装,规避多层包装的问题。
  • 如果排查发现是存入集合的自定义对象的hashCode、equals方法中又触发了集合的add操作,调整对应逻辑,避免递归调用。

内容的提问来源于stack exchange,提问作者James Fu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 23:57:04