为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

PIPIONE 2019-06-19 15:39:36
Java中对象的内存消耗是多少?一个具有100个属性的对象占用的内存空间是否与100个对象的内存空间相同,每个对象都有一个属性?为一个对象分配了多少内存?在添加属性时使用了多少额外的空间?
查看完整描述

3 回答

?
哈士奇WWW

TA贡献1799条经验 获得超6个赞

明德指出这不是一个直截了当的问题:

JVM可以随心所欲地以任何方式存储数据,无论是大端还是小端,有任何数量的填充或开销,尽管原语的行为必须像它们具有官方大小一样。
例如,jvm或本机编译器可能决定存储boolean[]在64位长的块中,就像BitSet..只要程序给出相同的答案,它就不必告诉你。

  • 它可能会在堆栈上分配一些临时对象。
  • 它可以优化某些变量或方法调用完全不存在,用常量替换它们。
  • 它可以对方法或循环进行版本化,即编译一个方法的两个版本,每个版本都针对特定的情况进行优化,然后预先决定要调用哪个版本。

当然,硬件和操作系统都有多层缓存,芯片缓存、SRAM缓存、DRAM缓存、普通RAM工作装置和磁盘上的备份存储。您的数据可能在每个缓存级别重复。所有这些复杂性意味着您只能非常粗略地预测RAM的消耗。

测量方法

你可以用Instrumentation.getObjectSize()获取对象消耗的存储的估计值。

若要可视化实际对象布局、占用空间和引用,可以使用JOL(Java对象布局)工具.

对象头和对象引用

在现代的64位JDK中,对象有一个12字节的头,填充到8个字节的倍数,所以最小的对象大小是16字节。对于32位JVM,开销为8字节,填充到4字节的倍数中.(来自德米特里·斯皮卡尔斯基的回答贾恩的回答,和JavaWorld.)

通常,32位平台或64位平台上的引用是4个字节,-Xmx32G;和超过32 GB的8个字节(-Xmx32G). (见压缩对象引用.)

因此,64位JVM通常需要30%-50%的堆空间。(我应该使用32位JVM还是64位JVM?,2012年,JDK 1.7)

装箱类型、数组和字符串

与原始类型相比,盒式包装器具有开销(来自JavaWorld):

  • Integer:16字节的结果比我预期的要差一点,因为int值只能容纳4个额外字节。使用Integer与将值存储为基元类型相比,占用300%的内存开销。

  • Long16字节:很明显,堆上的实际对象大小取决于特定CPU类型的特定JVM实现所做的低级别内存对齐。看上去像是Long是8字节的对象开销,加上实际长值的8字节。相反,Integer有一个未使用的4字节洞,很可能是因为我使用的JVM在一个8字节的单词边界上强制对象对齐。

其他集装箱也很昂贵:

  • 多维阵列它提供了另一个惊喜。
    开发人员通常使用类似于int[dim1][dim2]在数值和科学计算方面。

    int[dim1][dim2]数组实例,每个嵌套int[dim2]数组是Object以它自己的权利。每个数组都增加了通常的16字节数组开销。当我不需要一个三角形或粗糙的数组时,这代表了纯粹的开销。当数组尺寸相差很大时,影响会增大。

    例如,int[128][2]实例需要3600字节。与1,040字节相比,int[256]实例使用(具有相同的容量),3,600个字节表示246%的开销。在极端情况下byte[256][1],开销因素几乎是19!将其与C/C+的情况进行比较,在这种情况下,相同的语法不会增加任何存储开销。

  • String*aString内存增长跟踪其内部char数组的增长。String类添加另24个字节的开销。

    对于一个非空的人String在大小为10个或更小的字符中,所增加的开销相对于有用的有效负载(每个字符为2个字节,长度为4个字节),从100%到400%不等。

对齐

考虑一下这个示例对象:

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}

天真的求和意味着X将使用17个字节。但是,由于对齐(也称为填充),JVM以8字节的倍数分配内存,因此它将分配24个字节,而不是17个字节。


查看完整回答
反对 回复 2019-06-19
?
潇湘沐

TA贡献1816条经验 获得超6个赞

它依赖于体系结构/JDK。对于现代的JDK和64位架构,对象有12字节的头,填充8字节,所以最小对象大小是16字节。您可以使用一个名为Java对象布局若要确定对象的大小和获取任何实体的对象布局和内部结构的详细信息,或通过类引用猜测此信息。Integer在我的环境中的输出示例:

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/AInstance size: 16 bytes (estimated, the sample instance is not available)Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

因此,对于Integer,实例大小为16字节,因为4字节int紧压在标头后面和填充边界之前。

代码示例:

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

如果你使用Maven,就可以得到Jol:

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.3.2</version></dependency>


查看完整回答
反对 回复 2019-06-19
  • 3 回答
  • 0 关注
  • 737 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信