内推
【长期有效】欢迎加入字节跳动我的团队:内推链接
0x1.异常概览
java.lang.StackOverflowError
java.util.AbstractList$SubAbstractList.listIterator(AbstractList.java:308)
java.util.AbstractList$SubAbstractList.listIterator(AbstractList.java:308)
......
java.util.AbstractList$SubAbstractList.listIterator(AbstractList.java:308)
java.util.AbstractList$SubAbstractList.listIterator(AbstractList.java:308)
java.util.AbstractList$SubAbstractList.iterator(AbstractList.java:301)
java.util.AbstractCollection.toArrayList(AbstractCollection.java:349)
java.util.AbstractCollection.toArray(AbstractCollection.java:339)
java.util.Collections.sort(Collections.java:1863)
此crash只出现于Android 4.4及以下系统(<=JDK 6),而5.0(>=JDK 7)及以上版本系统未出现。
0x2.分析与解决
1)由于是特定系统版本bug,故上androidxref查看对应系统版本源码。(Android 4.4)
2)再观崩溃堆栈,Collections.sort(Collections.java:1863)方法中,会调用List.toArray方法再进行排序。Collections.sort如下:
Question:直观上看代码,mNewCommingUsersTemp是一个ArrayList,ArrayList自己实现了toArray,不应该走到AbstractCollection.toArray(AbstractCollection.java:339),而且StackOverflow是由于AbstractList$SubAbstractList.listIterator(AbstractList.java:308)递归调用发生的。
Answer:所以可以肯定mNewCommingUsersTemp的引用指向应该从ArrayList对象变为了一个实现了List接口的其他对象。mNewCommingUsersTemp重新赋值就这一句:mNewCommingUsersTemp = mNewCommingUsersTemp.subList(0, NEW_COMMING_LIST_MAX_SIZE),所以基本锁定到subList的锅了。
3)关于subList方法。
mNewCommingUsersTemp一开始是个ArrayList对象,所以去找找源码中的subList方法,发现ArrayList并没有subList方法,在其父类AbstractList中找到了实现。
也就是每次subList方法都会新建个SubAbstractList对象,而它的实现方式是,引用父list,并记录sub的位置而已&