2

找了很久关于java对象的大小,有很多这样的答案大家都在告诉我java对象的开销大小,以及如何计算出实际大小。但是他们怎么知道呢?我没有从官方的甲骨文文件中找到任何证据。这个结论的证据是什么?或者数据只是来自一些基于一些实验的猜测?

另一件事。官方文件中提到有一种“近似”的方法来测量物体 - Instrumentation方法,有人可以向我解释一下“近似”是什么意思吗?什么时候准确,什么时候不准确。最好有证据。

4

4 回答 4

5

如何计算出实际大小。但是他们怎么知道呢?

从经验。

我没有从官方的甲骨文文件中找到任何证据。

它取决于JVM。对于基于 OpenJDK 的 JVM,32 位 JVM 的标头大小与 64 位 JVM 不同,因为标头包含一个引用。其他 JVM 可能再次不同。

或者数据只是来自一些基于一些实验的猜测?

本质上,是的。

有人可以向我解释“大约”是什么意思吗?

当你测量一个物体的大小时,它可能意味着很多不同的东西

  • 物体有多大?(浅深度)
  • 它使用多少内存?(对象分配是 8 字节对齐的,即总是 8 的倍数)
  • 对象和所有引用的对象使用了多少空间?(深度)
  • 如果丢弃它,可以释放多少空间?(有多少对象被共享,它是否出现在两个已释放内存片段的中间)
  • 您计算堆栈上使用的空间还是堆外内存中使用的空间?

鉴于根据您需要知道的内容,您可以有许多不同的答案,因此有一个数字与您用于计算的所有这些数字大致接近是很有用的。


使用运行时遇到的问题是 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
于 2012-09-03T11:33:09.737 回答
2

我认为答案只能是经验性的,因为它取决于实现

Java 虚拟机不要求对象有任何特定的内部结构。

于 2012-09-03T11:16:03.413 回答
1

对我来说,最好的方法是最实际的方法,使用

long memTaken() {
  final Runtime rt = Runtime.getRuntime();
  return rt.totalMemory() - rt.freeMemory();
}
  1. 记住首字母memTaken()
  2. 制作一百万个对象的数组(调整此数字以适合您的堆);
  3. memTaken()从记忆中减去。

过程中可能会有一些暂时的分配,所以还需要运行GC。不提供任何保证System.gc(),但这种方法一直对我有用:

for (int i = 0; i < 3; i++) { System.gc(); Thread.sleep(50); }

您必须小心确保这会产生稳定的结果。例如,一种方法是计算几个不同对象计数的内存负载并比较结果。他们应该都匹配他们给出的内存/实例答案。

我以前曾建议过这个,因为蹩脚的解决方案而被拒绝,被建议使用适当的工具等等。所以我使用了工具,例如jvisualvm——它给出了错误的结果。这种方法从来没有给我错误的结果

于 2012-09-03T11:32:44.127 回答
0

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的保留大小是多少?和乙?使用探查器计算保留大小(大多数探查器为此使用静态堆分析)。

于 2012-09-03T11:52:31.870 回答