【JAVA中的对象】

对象基础

创建方式

JAVA是一门面对对象的语言,几乎是处处皆对象。在JAVA语言中,创建对象可以有多种方式,可以直接new,可以反射,可以反序列化等等。

对象的创建

第一步:类加载

(1)拿new为例,当虚拟机执行new时,就会去查找这个对象的类有没有被加载过,具体点就是虚拟机回到常量池中定位一下该类有没有具体的符号引用,如果没有那么就去加载这个类。

第二步:内存分配

(2)当类加载完成以后,就可以给这个对象分配内存了,因为这个对象所占用的内存大小,在类加载的时候完全是可以计算得到的。分配内存具体点来说就是在java的堆上分割下来一块区域。考虑这个场景,假设JAVA的堆内存是严格的分为了两块:
在这里插入图片描述中间有一个指针,指针左边是已用,右边是未用,那么这个操作其实就是把指针右移动一点。
存在的问题:单个线程肯定是没有问题的,但是在多线程的状态下,由于堆是所有线程共享的,所以会出现这样的场景:正在给第一个线程分配内存,指针还没修改,第二个线程继续用了原来指针的位置来分配内存,所以这是线程不安全的。
解决方案:对于这种问题,其实并不困难,一个很简单的解决方案就是对那个位置指针做同步处理,当然这并不是一个十分理想的状态,大多数虚拟机采用的是预分配内存的解决方案。
TLAB:为了解决这种问题,虚拟机给了每个线程一个线程预分配缓冲区,叫做:Thread Local Allcation Buffer。如果线程需要内存的分配,直接使用该缓冲区,缓冲区不够了再去堆上请求,这样其实很大程度上能够减轻线程直接请求堆上的内存,这样就不需要很多的同步操作,当然了,缓冲区去堆上请求,是需要同步的。

初始化设置

内存分配完毕之后,这个时候虚拟机会把内存的值全部置零,当然,如果是从TLAB上拿下来的,这块本来就是0,因为TLAB从堆上拿的时候就做了这些操作,然后虚拟机会对对象做一些必要的设置。比如hashcode,GC时候年龄分区等等。这些信息一般都是直接储存在对象头内部。

赋值

其实到了这里,虚拟机的工作已经完成了,但是在程序开来,对象才刚刚创建,因为一些赋值操作还没有做,所有的字段还都是0,所以会有一些对象内部的赋值操作来初始化一些变量的之。
到了这里,一个对象才是真的创建了起来

对象的内存布局

在Hotpot虚拟机中,对象在内存中可以分为三个区域,对象头,实例化数据,和对齐填充。
对象头:对象头其实存了这个对象一些必要的信息,比如hashcode,GC分代标志等等。当然对象头里面有一个重要的东西:类型指针。这个指针指向了对象的元数据,用来标识它是属于哪个类的。如果是数组,那么对象头还会存一下数组的长度,这也就是为什么我们用java数组的时候,数组长度直接就是数组的一个属性。
实例化数据:这一区域其实才是真正有用的,有我们封装进来的所有信息,包括继承父类的等等。
对齐填充:这个没有大的作用,只是为了内存对齐用的。(什么叫内存对齐??额,这个,可以自行百度,挺简单的一个概念)

对象的访问

这个其实没有太大的作用,虚拟机栈上有一个指向堆中的引用,通过这个引用来分为堆的对象。(因为对象都是在堆里面)

以上,就是对象的内容。

发布了370 篇原创文章 · 获赞 48 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_41863129/article/details/103757288