在哪里可以找到如何计算java对象大小的证据

我已经搜索了很长时间的java对象的大小,有很多这样的答案,每个人都告诉我java对象的开销大小,以及如何计算出实际大小。 但他们怎么知道呢? 我没有从官方的oracle文件中找到任何证据。 这个结论有什么证据? 或者数据来自一些基于某些实验的猜测?

另一件事。 在官方文件中提到有一种“近似”的方法来衡量对象 – 仪器方式,任何人都可以向我解释什么是’近似’的意思? 什么时候准确,什么时候不准确。 最好有证据。

如何计算出实际尺寸。 但他们怎么知道呢?

来自经验。

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

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

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

基本上,是的。

任何人都可以向我解释什么是’近似’的意思?

当您测量对象的大小时,它可能意味着许多不同的事情

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

根据您需要知道的情况,您可以获得许多不同的答案,有一个数字与您用于计算的所有数字大致接近是很有用的。


使用Runtime遇到问题的地方是TLAB在大块中分配数据。 可以以multithreading方式进一步分配这些大块。 缺点是你没有获得准确的内存使用信息。

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. 

关闭-XX:-UseTLAB ,你会看到-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(); } 
  1. 记住初始的memTaken() ;
  2. 创建一个百万个对象的数组(调整这个数字以适合你的堆);
  3. 从记住的memTaken()减去memTaken()

在此过程中可能存在一些瞬态分配,因此您还需要运行GC。 System.gc()没有提供任何保证,但这种方法一直对我有用:

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

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

我之前已经建议过,已经放下了跛脚解决方案,建议使用正确的工具等等。所以我使用了工具,例如jvisualvm - 它给出了错误的结果。 这种方法从来没有给错误的结果

java对象有两种不同的大小:浅大小和保留大小。 对象的浅大小是其所有字段的大小的总和:原始成员的直接前导,以及每个非原始成员的指针大小(这在32和64位体系结构之间变化)。 您可以使用instrumantation在运行时找到对象的浅尺寸。 这是一个很好的教程

保留大小由堆空间定义,当对象被吞噬时将释放该空间。 找到对象的保留大小并非易事,主要是因为对象通常由其他对象组成。 例如:

 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; } } 

什么是保留的大小? 和b? 使用分析器来计算保留的大小(大多数分析器都使用静态堆分析)。