当使用List中的切片操作时,导致内存溢出错误。
定义一个名为 data 的静态 List 来存放 Integer 的 List,也就是说 data 的
成员本身是包含了多个数字的 List。循环 1000 次,每次都从一个具有 10 万个 Integer 的
List 中,使用 subList 方法获得一个只包含一个数字的子 List,并把这个子 List 加入 data
变量:
private static List<List<Integer>> data = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
List<Integer> rawList = IntStream.rangeClosed(1, 100000).boxed().collect(Collectors.toList());
data.add(rawList.subList(0, 1));
}
导致内存溢出,是因为循环中的 1000 个具有 10 万个元素的 List 始终得不到回收,因为
它始终被 subList 方法返回的 List 强引用。这里的subList()方法并不是创建了一个新的集合,而是引用了旧的集合中的元素,导致之间有关系无法被垃圾回收。又由于强引用
的特性直至OOM也不会进行垃圾处理
。
SubList 相当于原始 List 的视图,那么避免相互影响的修复方式有两种
一种是,不直接使用 subList 方法返回的 SubList,而是重新使用 new ArrayList,在构
造方法传入 SubList,来构建一个独立的 ArrayList;
另一种是,对于 Java 8 使用 Stream 的 skip 和 limit API 来跳过流中的元素,以及限制
流中元素的个数,同样可以达到 SubList 切片的目的。
//方式一:
List<Integer> subList = new ArrayList<>(list.subList(1, 4));
//方式二:
List<Integer> subList = list.stream().skip(1).limit(3).collect(Collectors.toList());