b站一面 Object o = new Object();占几个字节

对象的内存分布

在 Hotspot VM 中,对象在内存中的存储布局分为 3 块区域:

  • 对象头(Header)
  • 实例数据(Instance Data)
  • 对齐填充(Padding)

对象头又包括三部分:MarkWord、元数据指针、数组长度。

  • MarkWord:用于存储对象运行时的数据,好比 HashCode、锁状态标志、GC分代年龄等。这部分在 64 位操作系统下占 8 字节,32 位操作系统下占 4 字节。
  • 指针:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪一个类的实例。
    这部分就涉及到指针压缩的概念,在开启指针压缩的状况下占 4 字节,未开启状况下占 8 字节。
  • 数组长度:这部分只有是数组对象才有,若是是非数组对象就没这部分。这部分占 4 字节。

实例数据就不用说了,用于存储对象中的各类类型的字段信息(包括从父类继承来的)。再来复习一遍8种基本数据类型所占字节数:

boolean 1byte

byte 1 byte

char 2 byte

short 2 byte

int 4 byte

long 8 byte

float 4 byte

double 8 byte

关于对齐填充,Java 对象的大小默认是按照 8 字节对齐,也就是说 Java 对象的大小必须是 8 字节的倍数。若是算到最后不够 8 字节的话,那么就会进行对齐填充。

关于指针压缩

引用类型在 64 位系统上占用 8 个字节,虽然一个并不大,但是耐不住多。

所以为了解决这个问题,JDK 1.6 开始 64 bit JVM 正式支持了 -XX:+UseCompressedOops (需要jdk1.6.0_14) ,这个参数可以压缩指针。

启用 CompressOops 后,会压缩的对象包括:

  • 对象的全局静态变量(即类属性);
  • 对象头信息:64 位系统下,原生对象头大小为 16 字节,压缩后为 12 字节;
  • 对象的引用类型:64 位系统下,引用类型本身大小为 8 字节,压缩后为 4 字节;
  • 对象数组类型:64 位平台下,数组类型本身大小为 24 字节,压缩后 16 字节。

当然压缩也不是万能的,针对一些特殊类型的指针 JVM是不会优化的。 比如:

  • 指向非 Heap 的对象指针
  • 局部变量、传参、返回值、NULL指针。

JVM在1.6之后,在64位操作系统下都是默认开启指针压缩的。

查看对象在内存中的分布和占用情况

maven项目下导入 jol-core:

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

测试代码:

public class ObjectCore {
    public static void main(String[] args) {
        Obj obj = new Obj();
        ClassLayout classLayout1 = ClassLayout.parseInstance(obj);
        System.out.println(classLayout1.toPrintable());
        Double i = 1000.0;
        ClassLayout classLayout2 = ClassLayout.parseInstance(i);
        System.out.println(classLayout2.toPrintable());
    }
}

class Obj {
    Integer i;
}

输出结果:

参考资料:

高端面试必备:一个Java对象占用多大内存 - rickiyang - 博客园

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当在 Android 中遇到 "Parcelable encountered IOException writing serializable object" 错误时,这通常是由于递的对象没有正确实现 `Parcelable` 接口而导致的。要解决这个问题,您可以尝试以下几种方法: 1. 实现 Parcelable 接口:确保要传递的对象正确地实现了 Parcelable 接口。Parcelable 接口提供了一种序列化和反序列化对象的方式,以便在 Android 组件之间进行传递。您可以按照以下步骤实现 Parcelable 接口: - 在要传递的对象类中实现 Parcelable 接口。 - 实现 `writeToParcel(Parcel dest, int flags)` 方法,将对象的属性写入 Parcel 对象。 - 实现 `describeContents()` 方法,返回 0。 - 添加一个名为 `CREATOR` 的 `Parcelable.Creator` 对象,并实现 `createFromParcel(Parcel source)` 和 `newArray(int size)` 方法。 2. 序列化对象:如果您不需要使用 Parcelable 接口,而是希望使用 Java 的序列化机制,您可以确保要传递的对象正确地实现了 Serializable 接口。Serializable 接口提供了一种将对象序列化为字节流的机制,以便在 Java 中进行传递。请确保要传递的对象及其所有嵌套对象都实现了 Serializable 接口。 3. 检查对象中的属性:当一个对象实现了 Parcelable 或 Serializable 接口时,其所有嵌套属性也必须是可序列化的。请确保对象中的所有属性都实现了 Parcelable 或 Serializable 接口。 4. 避免传递大型对象:尽量避免传递大型对象,特别是 Bitmap 等占用大量内存的对象。如果传递大型对象是必需的,可以考虑其他方式,如使用文件或数据库进行传递。 通过以上方法,您应该能够解决 "Parcelable encountered IOException writing serializable object" 错误。如果问题仍然存在,请检查错误日志以获取更详细的信息,并在需要时提供相关代码以便更好地帮助您解决问题。如有任何疑问,请随时向我提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值