Java中对象的内存消耗是多少?

Java中对象的内存消耗是多少?,java,memory,footprint,Java,Memory,Footprint,一个具有100个属性的对象所消耗的内存空间是否与100个具有一个属性的对象所消耗的内存空间相同 为一个对象分配了多少内存? 添加属性时使用了多少额外空间?否,注册对象也需要一些内存。具有1个属性的100个对象将占用更多内存。不,100个小对象需要的信息(内存)比一个大对象多。每个对象都有一定的开销用于其关联的监视器和类型信息,以及字段本身。除此之外,几乎可以按照JVM认为合适的方式(我相信)布局字段,但至少有些JVM会非常紧凑地打包。考虑这样一个类: public class SingleByt

一个具有100个属性的对象所消耗的内存空间是否与100个具有一个属性的对象所消耗的内存空间相同

为一个对象分配了多少内存?

添加属性时使用了多少额外空间?

否,注册对象也需要一些内存。具有1个属性的100个对象将占用更多内存。

不,100个小对象需要的信息(内存)比一个大对象多。

每个对象都有一定的开销用于其关联的监视器和类型信息,以及字段本身。除此之外,几乎可以按照JVM认为合适的方式(我相信)布局字段,但至少有些JVM会非常紧凑地打包。考虑这样一个类:

public class SingleByte
{
    private byte b;
}
vs

在32位JVM上,我希望100个
SingleByte
实例占用1200字节(由于填充/对齐,8字节的开销+4字节的字段)。我希望一个100字节的
OneHundredBytes
实例占用108字节的开销,然后压缩100字节。当然,它可能因JVM而异-一个实现可能会决定不将字段打包为
OneHundredBytes
,这会导致占用408字节(=8字节开销+4*100对齐/填充字节)。在64位JVM上,开销也可能更大(不确定)

编辑:见下面的评论;显然,热点填充到8字节边界,而不是32字节,因此
SingleByte
的每个实例将占用16字节

无论哪种方式,“单个大对象”的效率至少与多个小对象相同——对于这样的简单情况。

指出,这不是一个简单的问题:

JVM可以自由地在内部以任何方式存储数据,不管大小,不需要任何填充或开销,尽管原语的行为必须与官方大小相同。
例如,JVM或本机编译器可能决定将
布尔[]
存储在64位长的块中,如
位集
。它不必告诉你,只要程序给出相同的答案

  • 它可能会在堆栈上分配一些临时对象
  • 它可能会优化一些完全不存在的变量或方法调用,并用常量替换它们
  • 它可能会对方法或循环进行版本化,即编译一个方法的两个版本,每个版本针对特定情况进行了优化,然后预先决定调用哪个版本
当然,硬件和操作系统有多层缓存、片上缓存、SRAM缓存、DRAM缓存、普通RAM工作集和磁盘备份存储。您的数据可能会在每个缓存级别重复。所有这些复杂性意味着您只能非常粗略地预测RAM消耗

测量方法 您可以使用获取对象消耗的存储的估计值

要可视化实际对象布局、示意图和参照,可以使用

对象头和对象引用 在现代64位JDK中,一个对象有一个12字节的头,填充为8字节的倍数,因此最小对象大小为16字节。对于32位JVM,开销为8字节,填充为4字节的倍数。(来自,和)

通常,32位平台或64位平台上的引用为4字节,最大为
-Xmx32G
;32Gb以上的8个字节(
-Xmx32G
)。(见附件。)

因此,64位JVM通常需要增加30-50%的堆空间。(,2012,JDK 1.7)

装箱类型、数组和字符串 与基元类型相比,盒装包装器具有开销(从):

  • Integer
    :16字节的结果比我预期的稍差,因为
    int
    值只能容纳4个额外字节。与可以将值存储为基元类型相比,使用
    整数
    会消耗300%的内存开销

  • Long
    :16字节也很明显,堆上的实际对象大小取决于特定JVM实现针对特定CPU类型执行的低级内存对齐。看起来
    Long
    是8字节的对象开销,加上8字节的实际Long值。相反,
    Integer
    有一个未使用的4字节洞,很可能是因为我使用的JVM强制对象在8字节字边界上对齐

其他容器也很昂贵:

  • 多维数组:它提供了另一个惊喜。
    开发人员通常在数值和科学计算中使用类似于
    int[dim1][dim2]
    的结构

    int[dim1][dim2]
    数组实例中,每个嵌套的
    int[dim2]
    数组本身就是一个
    对象。每个都会增加通常的16字节数组开销。当我不需要三角形或参差不齐的数组时,这表示纯开销。当数组维度差异很大时,影响会增大

    例如,一个
    int[128][2]
    实例需要3600字节。与
    int[256]
    实例使用的1040字节(具有相同的容量)相比,3600字节表示246%的开销。在
    字节[256][1]
    的极端情况下,开销系数几乎为19!与C/C++的情况相比,在C/C++中,相同的语法不会增加任何存储开销

  • String
    :字符串的内存增长跟踪其内部字符数组的增长。但是,
    字符串
    类又增加了24字节的开销

    对于大小不超过10个字符的非空
    字符串
    ,相对于有效负载(每个字符2个字节加上长度4个字节)增加的开销成本从100%到400%不等

对齐 考虑这一点:

一个简单的求和建议
X
的实例将使用17个字节。但是,由于对齐(也称为填充),JVM
public class OneHundredBytes
{
    private byte b00, b01, ..., b99;
}
class X {                      // 8 bytes for reference to the class definition
   int a;                      // 4 bytes
   byte b;                     // 1 byte
   Integer c = new Integer();  // 4 bytes for a reference
}
java.lang.Runtime.getRuntime();
 public class PerformanceTest {
     private static final long MEGABYTE = 1024L * 1024L;

     public static long bytesToMegabytes(long bytes) {
         return bytes / MEGABYTE;
     }

     public static void main(String[] args) {
         // I assume you will know how to create an object Person yourself...
         List <Person> list = new ArrayList <Person> ();
         for (int i = 0; i <= 100_000; i++) {
             list.add(new Person("Jim", "Knopf"));
         }

         // Get the Java runtime
         Runtime runtime = Runtime.getRuntime();

         // Run the garbage collector
         runtime.gc();

         // Calculate the used memory
         long memory = runtime.totalMemory() - runtime.freeMemory();
         System.out.println("Used memory is bytes: " + memory);
         System.out.println("Used memory is megabytes: " + bytesToMegabytes(memory));
     }
 }
Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

java.lang.Integer object internals:
 OFFSET  SIZE  TYPE DESCRIPTION                    VALUE
      0    12       (object header)                N/A
     12     4   int Integer.value                  N/A
Instance size: 16 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.util.VMSupport;

public static void main(String[] args) {
    System.out.println(VMSupport.vmDetails());
    System.out.println(ClassLayout.parseClass(Integer.class).toPrintable());
}
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.3.2</version>
</dependency>