当前位置: 首页 > 面试题库 >

Java 8构造函数参考的惊人性能和大堆占用空间?

孙才捷
2023-03-14
问题内容

我刚在生产环境中遇到了不愉快的经历, OutOfMemoryErrors: heapspace..

我将问题追溯到我ArrayList::new在函数中的使用。

为了验证它实际上是否比通过声明的构造函数(t -> new ArrayList<>())进行的正常创建更糟糕,我编写了以下小型方法:

public class TestMain {
  public static void main(String[] args) {
    boolean newMethod = false;
    Map<Integer,List<Integer>> map = new HashMap<>();
    int index = 0;

    while(true){
      if (newMethod) {
        map.computeIfAbsent(index, ArrayList::new).add(index);
     } else {
        map.computeIfAbsent(index, i->new ArrayList<>()).add(index);
      }
      if (index++ % 100 == 0) {
        System.out.println("Reached index "+index);
      }
    }
  }
}

在索引达到30k后立即运行方法newMethod=true;将导致方法失败OutOfMemoryError。使用newMethod=false;该程序不会失败,但是会不断努力直到被杀死(索引很容易达到150万)。

为什么在堆上ArrayList::new创建那么多Object[]元素以至于导致OutOfMemoryError如此之快?

(顺便说一句,当集合类型为时也会发生HashSet。)


问题答案:

在第一种情况下(ArrayList::new),您正在使用带有初始容量参数的构造函数,在第二种情况下,则不是。较大的初始容量(index在您的代码中)导致Object[]要分配的较大容量,从而导致OutOfMemoryErrors。

这是两个构造函数的当前实现:

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

在中发生了类似的事情HashSet,除了在add调用之前不分配数组。



 类似资料:
  • 为什么供应商只支持无参数构造函数? 如果默认构造函数存在,我可以这样做: 但如果唯一的构造函数采用字符串,我必须这样做:

  • 鉴于 IntelliJ IDEA 2016.1.1报告“可以替换为方法引用”。 我知道无参数构造函数的< code>Foo::new语法,但是不知道如何将< code>foo作为参数传入。我肯定漏掉了什么。

  • Kotlin中的参数与Java中有些不同。如你所见,我们先写参数的名字再写它的类型: fun add(x: Int, y: Int) : Int { return x + y } 我们可以给参数指定一个默认值使得它们变得可选,这是非常有帮助的。这里有一个例子,在Activity中创建了一个函数用来toast一段信息: fun toast(message: String, length: I

  • 实际上,我不明白无参数构造函数和默认构造函数的区别是什么。 在创建名为cFrame的Test对象时,是否调用此类的默认构造函数?

  • 问题内容: 其实我不明白,无参数构造函数和默认构造函数有什么区别。 创建名为cFrame的Test对象时,这是否调用此类的默认构造函数? 问题答案: 该构造函数是一个无参数的构造函数,代表您的Java编译器插入; 它包含对(not )的调用,这是默认行为。如果实现任何构造函数,则不再收到默认的构造函数。 JLS-8.8.9。默认构造函数说(部分), 如果一个类不包含构造函数声明,则隐式声明一个没有

  • 在经历冬眠3时。x文档我知道我们也可以为具有私有可见性的POJO声明一个无arg构造函数,但文档说它有限制: 无参数构造函数是所有持久类的要求;Hibernate必须使用Java反射为您创建对象。构造器可以是私有的,但是在没有字节码插装的情况下,运行时代理生成和有效的数据检索需要包或公共可见性。 我不熟悉Hibernate,我试图了解何时使用运行时代理,何时使用字节码,以及这在Hibernate中