Java 不同的可用堆大小

标签 java heap-memory

我刚刚发现有一些库可以计算java对象的浅层大小,所以我想我也可以用一种非常简单的方式来编写它。这是我尝试过的。

  1. 使用Xmx(如A)启动程序
  2. 创建您想要计算大小的类型的对象(例如类型 T)并将它们存储在列表中,这样 GC 就不会清理它们。
  3. 当我们遇到 OOM 时,让代码处理它并清空列表。
  4. 现在检查我们分配的 T 类型对象的数量。设此为n
  5. 进行二分搜索找出增量,以便成功分配 n+1 对象。

这是代码,我尝试过

import java.util.ArrayList;
public class test {
    public static void main(String[] a) {
        ArrayList<Integer> l = new ArrayList<>();
        int i=0;
        try {
            while(true) {
                l.add(new Integer(1));
                i++;
            }
        } catch(Throwable e) {
        } finally {
            l.clear();
            System.out.println(i + "");
        }
    }
}

但我注意到每次运行中为同一 Xmx 分配的对象数量是不同的。为什么是这样? JVM内部有什么东西是随机的吗?

最佳答案

But I noticed that the number of objects allocated in each run for a same Xmx was varying. Why is this?

JVM 中的某些事件是不确定的,这可能会影响垃圾收集器的行为。

但是,可能存在一些因素,导致在填满堆之前创建的(您的)对象数量可变。其中包括:

  • 并非堆中的所有对象都是您显式创建的 ArrayListInteger 对象。当您调整 ArrayList 的大小时,将会创建 Object[] 对象,由 println 调用生成的各种对象......以及其他东西这发生在幕后。

  • 堆大小调整行为。堆的大小不会立即调整为 -Xmx 大小。 JVM 通常以较小的堆大小开始,并根据需要扩展它。当您获得 OOME 时,JVM 很可能已将堆扩展至允许的最大值,但扩展的顺序可能对……各种因素敏感,包括一些可能不确定的因素。

  • 堆代。典型的 Java GC 使用旧空间和新空间。旧空间包含长寿的对象。新对象被分配到新空间......除非它们非常大。对象的实际分布会影响 GC 运行的时间以及 JVM 决定堆已满的时间。

  • JIT 编译。在应用程序执行的某些时刻,JVM(通常)会决定 JIT 编译您的代码。发生这种情况时,会分配额外的对象。


Is there anything inside JVM randomized?

显式随机化不太可能影响该基准。在各个级别(即硬件、操作系统和 JVM)都存在足够的不确定性来解释您所看到的不一致结果。


简而言之:我不希望您的基准测试能够针对可创建的对象数量提供一致的结果。

关于Java 不同的可用堆大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53577013/

相关文章:

java - 为什么 Java 8 有 Arrays.parallelSort() 但没有 Collections.parallelSort()?

java - DocumentBuilder 中 setNamespaceAware 的用途是什么?

java - 生成具有随机行长度的随机二维数组

java - 30-100GB 大堆的高效 GC 收集

访问堆对象与堆栈对象的 C++ 性能

c++ - 在额外函数中使用 delete/new 时堆损坏

java - 找不到 fragment ID 的 View

java - MOXy:抛出实体类型与处理程序返回值不同的 WebApplicationException

c++ - 为什么需要指针来初始化堆上的对象,而不是堆栈上的对象?

c - 我怎样才能告诉 Linux 进程使用一个文件作为它的整个堆?