zoukankan      html  css  js  c++  java
  • Java中List集合中subList的坑

    参考博主http://blog.csdn.net/xuweilinjijis/article/details/9037635

    先看List接口subList方法的javadoc 

     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集合中的元素,只是改变了开始位置和结束为止而已.如果修改返回对象的数据,那么原对象对应的值也会被修改。
    看一下List接口具体实现类 ArrayList类,其中的subList方法源码如下
    public List<E> subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);//检查是否越界
            return new SubList(this, 0, fromIndex, toIndex);//返回截取之后的对象
        }
    

     再接着看一下 SubList类的构造器,JDK源码如下,其实 SubList就是ArrayList中的一个内部类(非静态的),

     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());
            }
    

      运行结果

          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)

    看到只包含815个元素就内存溢出啦。就是因为子对象一只引用着父对象,导致父对象无法回收。从而内存溢出

         




  • 相关阅读:
    一个例子说明如何在DataSnap中使用FireDAC
    DataSnap Demo:TFDConnection、最大连接数、客户端回叫功能、多线程模拟、压力测试等
    DataSnap Demo:TFDConnection、最大连接数、客户端回叫功能、多线程模拟、压力测试等
    Delphi2010中DataSnap技术网摘
    Delphi2010中DataSnap技术网摘
    推荐大家使用的CSS书写规范、顺序
    Windows autoKeras的下载与安装连接
    vscode Python 运行环境配置
    react框架
    关于k Line Chart (k线图)
  • 原文地址:https://www.cnblogs.com/09120912zhang/p/8301585.html
Copyright © 2011-2022 走看看