java内存一般占多少_你的java对象占了多大的内存?

刚开始学习java的时候,知道了继承的概念,子类会继承父类的属性,private和default(不在一个包时)的除外。当时不明白父类和子类是怎么保存属性的值,但是了解了JOL后,终于有机会解开这个长时间困扰心头的问题。

首先,网上有一种说法,当你创建一个子类对象的时候会同时创建一个父类对象,并且子类对象会有一个指针指向父类的对象,对于这个说法我表示怀疑,因为这样的话,那你创建一个对象的时候会有很多对象创建出来,这种设计方式太浪费内存。今天就来用JOL验证一下是否是这样的。(注:本次实验的对象大小是建立在指针压缩的情况下的,指针不压缩时不影响本实验的结果,只是对象的大小不同)

首先,你需要导入JOL包

org.openjdk.jol

jol-core

0.9

之后我们先看第一个问题:一个Object类对象占用多大的内存

public class JolTest {

public static void main(String[] args) {

Object o = new Object();

System.out.println(ClassLayout.parseInstance(o).toPrintable());

}

}

执行上面的代码结果如下

4b92624a8b1addfc20c6842a9fe017cd.png

可以看到一个Object占有16个字节,前12个字节是对象头,后4个字节是java为了对齐使用的补充数据,一个java对象的大小总是8的整数倍

之后我们尝试创建一个类,包含一个int型的变量,看看它的对象在内存中是什么样的

public classJolTest {public static voidmain(String[] args) {

Object o= newParent();

System.out.println(ClassLayout.parseInstance(o).toPrintable());

}

}classParent{private intage;

}

执行结果如下

e8985ea0e7a3003f580d5dd5fe915124.png

仍然是16个字节,但是不同的是12-15这4位不在是alignment,而是int,我们知道int类型占有4个字节

之后我们写一个类继承Parent,看看它的情况

public classJolTest {public static voidmain(String[] args) {

Object o= newChild();

System.out.println(ClassLayout.parseInstance(o).toPrintable());

}

}classParent{private intage;

}class Child extendsParent{private intage;

}

49132ec48cf9a189e1be05da59eb1668.png

从执行结果中我们可以看出,子类中拥有一个对象Parent.age,并没有指向父类的指针,因此我们可以得出结论,创建子类对象时只会得到一个子类的对象,但是子类对象中会包含父类的属性,即使该属性是private的,即使该属性和父类的属性同名

最后我们来使用byte类型替代int来试一下结果是否有所不同,我们知道byte类型占据一个字节,我们在创建一个Child的子类

public classJolTest {public static voidmain(String[] args) {

Object o= newLast();

System.out.println(ClassLayout.parseInstance(o).toPrintable());

}

}classParent{private byteage;private bytesex;

}class Child extendsParent{private byteage;

}class Last extendsChild{private booleansex;

}

执行程序,结果如下:

426b7618459d5e2796555be87511ab0e.png

我们注意到一点,当父类的属性不足4个字节时,会在后面加上alignment,我们称之为类内属性对齐(顺带一提,关闭指针压缩时,类内属性对齐将不是4个字节为单位,而是8个字节)。

现在不知得到了我想要的答案,而且有额外的以下三种收获:

1.如何计算一个对象的大小(启用指针压缩时):((12 + 自己属性的大小 + 自己所有祖先类的属性的大小 + 4)/ 8) * 8,自己属性的大小计算方式是:((属性的大小 + 3) / 4 ) * 4,祖先类的属性大小为每个祖先的大小之和(计算内属性对齐);以最后的代码为例,new Parent的时候占用的内存大小为 ((12 +(( 2 + 3)/4) * 4 + 4) / 8) * 8 = 18,new Child: ((12 + ((2 + 3)/ 4) * 4 + ((1 + 3)/4) * 4  + 4) / 8) *8 = 24;同样可得new Last占用的字节也是24位。至于关闭指针压缩的公式,大家理解了公式后可以自行推到出来,需要注意的就是此时类内属性对齐是8个字节为一组。

2.另一个不支持深度继承的依据,不会使用的父类属性也会对对象的大小造成影响。

3.在需要严格控制的对象(一般是在项目中会大量创建的类对象)中,是使用继承还是组合需要考虑一下,毕竟继承可能会浪费属性,而组合会浪费对象头和alignment,如果仅从对象大小来考虑,如果继承的属性存在必要的,建议使用继承;如果全都是非必要的,可以使用组合,在需要该属性的时候再创建对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值