找了很久关于java对象的大小,有很多这样的答案,大家都在告诉我java对象的开销大小,以及如何计算出实际大小。但是他们怎么知道呢?我没有从官方的甲骨文文件中找到任何证据。这个结论的证据是什么?或者数据只是来自一些基于一些实验的猜测?
另一件事。官方文件中提到有一种“近似”的方法来测量物体 - Instrumentation方法,有人可以向我解释一下“近似”是什么意思吗?什么时候准确,什么时候不准确。最好有证据。
如何计算出实际大小。但是他们怎么知道呢?
从经验。
我没有从官方的甲骨文文件中找到任何证据。
它取决于JVM。对于基于 OpenJDK 的 JVM,32 位 JVM 的标头大小与 64 位 JVM 不同,因为标头包含一个引用。其他 JVM 可能再次不同。
或者数据只是来自一些基于一些实验的猜测?
本质上,是的。
有人可以向我解释“大约”是什么意思吗?
当你测量一个物体的大小时,它可能意味着很多不同的东西
鉴于根据您需要知道的内容,您可以有许多不同的答案,因此有一个数字与您用于计算的所有这些数字大致接近是很有用的。
使用运行时遇到的问题是 TLAB 以大块的形式分配数据。这些大块可以进一步以多线程方式分配。缺点是您无法获得准确的内存使用信息。
static long memTaken() {
final Runtime rt = Runtime.getRuntime();
return rt.totalMemory() - rt.freeMemory();
}
public static void main(String... args) {
long used1 = memTaken();
Float i = new Float(0);
long used2 = memTaken();
System.out.println("new Float(0) used "+(used2 - used1)+" bytes.");
}
不带选项运行
new Float(0) used 0 bytes.
关闭 TLAB,你会看到-XX:-UseTLAB
new Float(0) used 336 bytes.
这比您预期的要高得多,因为必须加载类本身。如果您首先通过添加到开始创建 Float 的一个实例
Float j = new Float(1);
你得到
new Float(0) used 16 bytes
我认为答案只能是经验性的,因为它取决于实现:
Java 虚拟机不要求对象有任何特定的内部结构。
对我来说,最好的方法是最实际的方法,使用
long memTaken() {
final Runtime rt = Runtime.getRuntime();
return rt.totalMemory() - rt.freeMemory();
}
memTaken()
;memTaken()
从记忆中减去。过程中可能会有一些暂时的分配,所以还需要运行GC。不提供任何保证System.gc()
,但这种方法一直对我有用:
for (int i = 0; i < 3; i++) { System.gc(); Thread.sleep(50); }
您必须小心确保这会产生稳定的结果。例如,一种方法是计算几个不同对象计数的内存负载并比较结果。他们应该都匹配他们给出的内存/实例答案。
我以前曾建议过这个,因为蹩脚的解决方案而被拒绝,被建议使用适当的工具等等。所以我使用了工具,例如jvisualvm
——它给出了错误的结果。这种方法从来没有给我错误的结果。
java 对象有两种不同的大小:浅大小和保留大小。对象的浅大小是其所有字段大小的总和:原始成员的直接大小,以及每个非原始成员的指针大小(这在 32 位和 64 位体系结构之间变化)。您可以使用仪器在运行时找到对象的浅尺寸。这是一个很好的教程
保留大小由对象被垃圾时将释放的堆空间定义。找到对象的保留大小并非易事,主要是因为对象通常由其他对象组成。例如:
public class Clazz {
public byte[] member;
public static void main(String[] args) {
byte[] bytes = new byte[128];
Clazz a = new Clazz();
Clazz b = new Clazz();
a.member = bytes;
b.member = bytes;
}
}
a的保留大小是多少?和乙?使用探查器计算保留大小(大多数探查器为此使用静态堆分析)。