AbstractList$SubAbstractList.get java.lang.StackOverflowError的问题分析与解决

在项目开发过程中,遇到了这个崩溃,花费了了很多时间排查,仅以此文记录解决问题的思路和方式,以免后人再次踩坑。

  java.lang.StackOverflowError
        at java.util.AbstractList$SubAbstractList.get(AbstractList.java:292)
        at java.util.AbstractList$SubAbstractList.get(AbstractList.java:292)
        at java.util.AbstractList$SubAbstractList.get(AbstractList.java:292)
        at java.util.AbstractList$SubAbstractList.get(AbstractList.java:292)
        at java.util.AbstractList$SubAbstractList.get(AbstractList.java:292)
        at java.util.AbstractList$SubAbstractList.get(AbstractList.java:292)
        at java.util.AbstractList$SubAbstractList.get(AbstractList.java:292)
        at java.util.AbstractList$SubAbstractList.get(AbstractList.java:292)

该问题触发的条件:

Oppo R7s Android 4.4.4系统。
播放一条超过15s的音频的时候,在播放第二遍时,第12s会崩溃,且只有这一台手机有问题。

最后通过查资料,以及和@Cavabiao一起排查,发现是使用ArrayList的subList方法时触发的问题。

以下面这段代码为例(不想找项目代码了,一样的逻辑)

public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("");  
    for (int i = 0; i < 50000; i++) {
        list = list.subList(0, 1);
    }
    list.add("test");        
}

list = list.subList(0, 1); 该方法会触发递归, 当subList()方法调用且外面再加上一个循环的时候,最早的ListB= ListA.subList(),ListB持有他自己的Parent也就是ListA的引用, ListC= ListB.subList()。 以此循环 List50000= List49999.subList() 这样, 在List50000 调用自己的add remove 或者get方法时, 这几个方法里面,都需要调用其parent 来实现逻辑。那么以 List50000的 get方法为例,该get方法就需要以此递归调用List49999 List49998,List49997...ListC,ListB,LIstA 的get方法,这么多的递归调用极易造成栈溢出。

不过不同API Level的源码实现是不一样的,我们仅以API Level25 和API Level21 为例。

API Level25:

1)ArrayList.java:

1.png
2.png
3.png

可以看出ArrayList 类中,有个SubList的子类,
1)其里面的get set方法 只用到了elementData ,没有用到parent ,因为应该不会有递归调用的问题(未测试验证)
2) 其remove add方法,里面用到了parent的引用,因此会存在递归调用引发栈溢出的问题。

2)AbstractList.java:

4.png
5.png

AbstractList.java中 的SubList类中的 set get add remove等方法,均使用到parent(即l) 会存在递归调用引发栈溢出的问题。

API level21:

1)ArrayList.java:

没有SubList这个类

2)AbstractList.java:

6.png
7.png

可以看到AbstractList 中有个SubAbstactList类,该类的add addAll get remove set方法等,都用到了
parent的引用(即fullList) 那么这些方法会存在递归调用引发栈溢出的问题。

总结:

1)API Level 21 (Android 5.0) 23(Android6.0)(根据源码验证)
ArrayList 本身并没有实现SubList内部类,其subList()方法是直接使用父类AbstractList 中的SubList类实现
其set get add remove 方法中均用到了parent的引用,导致递归调用,易引发StackOverFlow的问题

2)API Level 25 (Android 7.1)(根据源码验证)
ArrayList 本身有实现SubList内部类,其subList()方法是直接使用ArrayList 中的SubList类实现,
而不是AbstactList 中的SubLIst类实现,所以
其set get 方法没有用到parent的引用,不会导致递归调用, 而其 add remove方法,用到了parent的引用,导致递归调用,易引发StackOverFlow的问题

3)其他的版本,比如API Level 22 (Android 5.1) API Level 24 (Android 7.0),因为没去看源码,故在此不做评论,但是依据代码的版本管理策略, API Level 22 (Android 5.1)应该和API Level 21 (Android 5.0)一致,而API Level 24 (Android 7.0)应该和 API Level 25 (Android 7.1) 一致,感兴趣的同学可以自行查阅。

因时间关系文章难免有疏漏,欢迎提出指正,谢谢。特别感谢@Cavabiao的协助排查。

参考文章:
1、慎用subList:ArrayList$SubList.add导致的java.lang.StackOverflowError

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,050评论 25 707
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,652评论 2 59
  • 许久没有联系的朋友忽然冒泡:最近还好吗? 坦白说,收到这种略显笨拙而突兀的问候其实并不舒服,感觉像是多年不串门的邻...
    写锦文阅读 567评论 0 0
  • 风啊迷住了四野迷住了眼睛而怀里的羽毛柔软充实我和我的大白鸟一跃而下在万尺高空的悬崖没有人到过的地方还是在梦里我和我...
    葺宝阅读 191评论 0 3
  • 今天是什么日子 起床:6点。 就寝:22:30 天气:大雨转小雨 心情:平静、喜悦、祥和 纪念日:同学WYJ的儿子...
    喜羊羊_43e1阅读 218评论 0 1