首页 > 编程知识 正文

java list sublistJava List的SubList使用问题,java的list使用

时间:2023-05-05 20:39:11 阅读:226703 作者:1581

一、Sublist导致OOM

代码

@Slf4jpublic classSubListDemo {public static voidsubListOOM() {

List> data = new ArrayList<>();for (int i = 0; i < 1000; i++) {

List rawList = IntStream.rangeClosed(1, 100000).boxed().collect(Collectors.toList());//构建一个100000个元素的list

data.add(rawList.subList(0, 1));

}

log.info("data.size(): " +data.size());

}

}

OOM

Exception in thread "File Watcher"java.lang.OutOfMemoryError: GC overhead limit exceeded

at java.io.File.listFiles(File.java:1212)

at org.springframework.boot.devtools.filewatch.FolderSnapshot.collectFiles(FolderSnapshot.java:63)

at org.springframework.boot.devtools.filewatch.FolderSnapshot.collectFiles(FolderSnapshot.java:67)

at org.springframework.boot.devtools.filewatch.FolderSnapshot.collectFiles(FolderSnapshot.java:67)

at org.springframework.boot.devtools.filewatch.FolderSnapshot.collectFiles(FolderSnapshot.java:67)

at org.springframework.boot.devtools.filewatch.FolderSnapshot.(FolderSnapshot.java:58)

at org.springframework.boot.devtools.filewatch.FileSystemWatcher$Watcher.getCurrentSnapshots(FileSystemWatcher.java:277)

at org.springframework.boot.devtools.filewatch.FileSystemWatcher$Watcher.scan(FileSystemWatcher.java:251)

at org.springframework.boot.devtools.filewatch.FileSystemWatcher$Watcher.run(FileSystemWatcher.java:236)

at java.lang.Thread.run(Thread.java:748)

Exception in thread"restartedMain"java.lang.reflect.InvocationTargetException

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:498)

at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded

at java.lang.Integer.valueOf(Integer.java:832)

at java.util.stream.IntPipeline$$Lambda$492/1604894031.apply(Unknown Source)

at java.util.stream.IntPipeline$4$1.accept(IntPipeline.java:250)

at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)

at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)

at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)

at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)

at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)

at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)

at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)

at com.example.newdemo.SubListDemo.subListOOM(SubListDemo.java:17)

at com.example.newdemo.NewdemoApplication.main(NewdemoApplication.java:13)

分析

出现 OOM 的原因是,循环中的 1000 个具有 10 万个元素的 List 始终得不到回收,因为它始终被 subList 方法返回的 List 强引用。

public List subList(int fromIndex, inttoIndex) {

subListRangeCheck(fromIndex, toIndex, size);return new SubList(this, 0, fromIndex, toIndex);

}

parent 字段就是原始的 List。SubList没有copy一份自己的数据,而是完整的保留了原始的list。 SubList 是原始 List 的视图,并不是独立的 List, SubList 强引用了原始的 List,所以大量保存这样的 SubList 会导致 OOM。

解决

不直接使用 subList 方法返回的 SubList,而是重新使用 new ArrayList,在构造方法传入 SubList,来构建一个独立的 ArrayList。sublist直接释放-》原始的list也被释放。

public static voidsubListWithoutOOM() {

List> data = new ArrayList<>();for (int i = 0; i < 1000; i++) {

List rawList = IntStream.rangeClosed(1, 100000).boxed().collect(Collectors.toList());//构建一个100000个元素的list

data.add(new ArrayList<>(rawList.subList(0, 1)));

}

log.info("data.size(): " +data.size());

}

另外一个例子

public static voidremoveSubList() {

List rawList = IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toList());

List subList = rawList.subList(0, 3);

subList.remove(0);

rawList.forEach(System.out::print);

}

2345678910

可以看到,移除sublist的元素后,直接影响到了原始list。

二、修改原始列表后SubList循环报错

测试代码

public static voidaddItemToOriginalList() {

List rawList = IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toList());

List subList = rawList.subList(0, 3);

rawList.add(11);try{

subList.forEach(System.out::print);

}catch(Exception ex)

{

ex.printStackTrace();

}

}

java.util.ConcurrentModificationException

at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1239)

at java.util.ArrayList$SubList.listIterator(ArrayList.java:1099)

at java.util.AbstractList.listIterator(AbstractList.java:299)

at java.util.ArrayList$SubList.iterator(ArrayList.java:1095)

at java.lang.Iterable.forEach(Iterable.java:74)

at com.example.newdemo.SubListDemo.addItemToOriginalList(SubListDemo.java:46)

at com.example.newdemo.NewdemoApplication.main(NewdemoApplication.java:13)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:498)

at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

分析

modCount 的字段,表示结构性修改的次数--影响list size修改测次数,add肯定影响size,导致modCount加1.但是sublist的modCount没有变,所有抛出了异常。

代码

private voidcheckForComodification() {if (ArrayList.this.modCount != this.modCount)throw newConcurrentModificationException();

}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。