参考博主 http://blog.csdn.net/xuweilinjijis/article/details/9037635
先看 List 接口 subList 方法的 javadoc
可以看到此方法其实就是直接指向原List集合中的元素,只是改变了开始位置和结束为止而已.如果修改返回对象的数据,那么原对象对应的值也会被修改.
The returned list is backed by this list, so non-structural
* changes in the returned list are reflected in this list, and vice-versa.
* The returned list supports all of the optional list operations supported
* by this list.
看一下List接口具体实现类 ArrayList类,其中的subList方法源码如下
再接着看一下 SubList 类的构造器, JDK 源码如下, 其实 SubList 就是 ArrayList 中的一个内部类 (非静态的),
public List < E > subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size); //检查是否越界
return new SubList(this, 0, fromIndex, toIndex); //返回截取之后的对象
}
下面是一段造成内存溢出的代码
private class SubList extends AbstractList < E > implements RandomAccess {
private final AbstractList < E > parent; //引用调用的父集合
private final int parentOffset; //父集合的起始位置
private final int offset; //原对象的起始位置
int size; //现在集合的大小
SubList(AbstractList < E > parent, int offset, int fromIndex, int toIndex) {
this.parent = parent; //从此处可以看到父集合一直被子集合引用着,只要子集合存在,父集合就不会被释放.从而容易造成内存溢出
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
}
运行结果
List < List < Integer >> cache = new ArrayList < List < Integer >> ();
try {
while (true) {
ArrayList < Integer > list = new ArrayList < >();
for (int j = 0; j < 100000; j++) {
list.add(j);
}
List < Integer > subList = list.subList(0, 1);
cache.add(subList);
}
} catch(Exception e) {} finally {
System.out.println("Cache Size=" + cache.size());
}
看到只包含 815 个元素就内存溢出啦.就是因为子对象一只引用着父对象,导致父对象无法回收.从而内存溢出
Exception in thread "main" Cache Size=815
java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.Integer.valueOf(Integer.java:832)
at com.effectJava.Chapter2.InstrumentedHashSet.main(InstrumentedHashSet.java:44)
来源: http://www.bubuko.com/infodetail-2464411.html