我刚刚发现有一些库可以计算java对象的浅层大小,所以我想我也可以用一种非常简单的方式来编写它。这是我尝试过的。
- 使用
Xmx
(如A
)启动程序 - 创建您想要计算大小的类型的对象(例如类型
T
)并将它们存储在列表中,这样 GC 就不会清理它们。 - 当我们遇到 OOM 时,让代码处理它并清空列表。
- 现在检查我们分配的
T
类型对象的数量。设此为n
- 进行二分搜索找出增量,以便成功分配
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 中的某些事件是不确定的,这可能会影响垃圾收集器的行为。
但是,可能存在一些因素,导致在填满堆之前创建的(您的)对象数量可变。其中包括:
并非堆中的所有对象都是您显式创建的
ArrayList
和Integer
对象。当您调整 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/