对象在内存中的布局分为普通对象和数组
普通对象
public class T {
private int m = 8;
public static void main(String[] args) {
// TODO Auto-generated method stub
T t = new T();
}
}
1.第一个markword也不太好翻译标记字,里面装的是锁相关信息何分代年龄。
2.第二个类型指针,比如说 new T()执向什么类型也就是T.class这种类型。
3.第三个实例数据也就是上图中的m。
4.第四个对齐就是说前三项字节数加起来不能对8整除,那么就补齐直到能被8整除。
markword和类型指针共同组成对象头,那么对象头里面具体包括什么呢?包含锁的信息,因为内容比较多。我会在下一篇博客为大家介绍。对象头以及锁升级
如果还不懂 我们来看一个例子程序,这里我们需要用到openjdk的一个工具,他可以很方便的让我看到一个对象的布局
maven地址:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
如果需要下载jar包,到maven仓库中下。
https://mvnrepository.com/artifact/org.openjdk.jol/jol-core/0.9
import org.openjdk.jol.info.ClassLayout;
public class T {
public static void main(String[] args) {
// TODO Auto-generated method stub
Object object = new Object();
String s = ClassLayout.parseInstance(object).toPrintable();
System.out.println(s);
}
}
我们来看一下打印信息
从第 0个字节 数4个字节 再从第4个字节再数4个字节总共组成markword 8个字节 再从第8个字节再数4个字节这就是指向这个类型的指针。 再从12个字节 数4个字节也就是咱们对齐的4个字节 因为前面总共加起来 4+8=12不够被8整除所以还要补齐4个字节。
为什么要补齐字节数直到能被8整除呢。
因为我们操作系统64位,那么寄存器也是64位,所以我们往里面扔东西最好事8个字节8个字节的扔,这样也不用划分区域什么的,为了提高效率,所以要被8整除。
为什么类型指针为4个字节。
这个还要具体看虚拟机是否压缩,因为虚拟机默认参数是要压缩的,这个后面我再讲。
那这个T对象又占多少字节呢?
public class T {
private int m = 8;
public static void main(String[] args) {
// TODO Auto-generated method stub
T t= new T();
String s = ClassLayout.parseInstance(t).toPrintable();
System.out.println(s);
}
}
答案是:16个字节 。可以看到新增加了一个int类型参数为4个字节,那么对齐部分就没有了。
那数组对象又是怎么布局的呢?
他和对象差不多我就不介绍了,有兴趣的可以自己去研究。
数组对象
一个比较坑的题目 Object objet = new Object()占用多少字节?
不是16字节吗?其实不是所以说这题比较坑,new Object() markword 8字节 classPointer 4字节 补齐 4字节 8+4+4=16 没错,但是这里还要加一个objet普通对象指针(ordinary object pointer缩写oops )4字节 8+4+4+4=20字节。。。。。
但是这也不一定,因为jvm自动帮我开启了压缩指针的一个命令。不信?我们来看。
打开cmd 输入java -XX:+PrintCommandLineFlags -version
这条命令的意思就是查看我们运行一个java默认的参数命令有哪些。
前两个一般人都能看懂,最小堆内存,最大堆内存。实际情况下一般将两者设置为一样。我们主要看UserCompressedClassPointers(压缩类指针)和UserCompressedOops(压缩普通对象指针Oops)
压缩类型指针就是值得我们对象头中的类型指针默认是8个字节而因为默认开启UserCompressedClassPointers所以为4字节
压缩普通对象指针就是一个类里面的引用数据默认是8个字节而因为默认开启UserCompressedOops所以为4字节。
不信?我们做个实验
import org.openjdk.jol.info.ClassLayout;
public class T1 {
private boolean aBoolean;
private byte aByte;
private short aShort;
private int anInt;
private long aLong;
private double aDouble;
private float aFloat;
private char aChar;
private String string;
private User user;
public static void main(String[] args) {
T1 t1 = new T1();
System.out.println(ClassLayout.parseInstance(t1).toPrintable());
}
}
class User{
String a;
}
我们先关闭 -XX:-UseCompressedClassPointers 类型指针压缩
我们再关闭 -XX:-UseCompressedOops
发现User和String指针都变成了8字节
总结:所以Object obj = new Object()一个 如果默认情况下是占用20个字节(merkword8字节+classponit4字节+对齐4字节+obj4字节),如果关闭压缩指令,那么就是占用也是20个字节(merkword8字节+classponit8字节+obj4字节),因为用不到补齐了,哈哈是不是被坑了。
好了至此总结完成,如果大家看了有收获,记得点个赞再走哦。以上内容都是看了马士兵老师的课总结下来,看了他讲jvm那张收获颇多,接下来我将继续总结