对象在内存中的布局

对象在内存中的布局分为普通对象和数组


                           普通对象

 

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那张收获颇多,接下来我将继续总结

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值