对象的创建--虚拟机过程

1.检查

​ 虚拟机遇到一个new 指令是,首先会检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并切检查这个符号引用代表的类是否已被加载,解析和初始化过.

​ 如果没有,则必须先执行相应的类加载过程;如果有,则会分配内存空间

2.分配内存空间

​ 对象所需内存的大小在类加载完成后便可确定,为对象分配空间的任务等同于吧一块确定大小的内存从Java 堆中划分出来.

​ a.指针碰撞分配

​ 假设Java 堆中内存是绝对规整的,所有用过的内存放在一边,空闲的内存放在另外一边,中间放着一个指针作为分界点的指示器,那所分配内存就净净把那个指针向空闲空间那边挪动一段与对象大小相等的距离

​ b.空闲列表分配

​ 如果Java 堆中内存是不规整的,已使用的内存和空间的内存相互交错,那就没有办法简答的进行指针碰撞,虚拟机就必须维护一个列表,记录哪些内存块是可用的,在分配时从列表中找到一块足够大的空间划分给对象实例,并更行表上的记录

​ 选择哪种分配方式由Java堆是否规整决定,而Java 堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定(Serial,ParNew 等带Compact 过程的收集器,采用指针碰撞分配方式;CMS 这种基于Mark-Sweep 算法使用空闲列表)

​ 对象创建是非常频繁的行为,仅仅修改一个指针所指向的位置,在并发情况下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没有修改,对象B又同时使用了原来的指针来分配内存情况

​ a.对分配内存空间的动作进行同步处理–原子性(采用CAS配上失败重试的方式)

​ b.把内存分配的动作按照线程划分再不同的空间中进行,即每个线程在Java 堆中预先分配一小块内存–本地线程分配缓存(使用TABLE)

3.初始化零值

​ 内存分配完成后,虚拟机需要将分配到空间都初始化零值(不包括对象头),如果是用TABLE,这一过程也可以提前至TABLE分配时完成,这样保证了对象的实例字段在Java 代码中可不赋初始值就直接使用

4.对象设置

​ 设置这个对象是那个类的实例,如何才能找到类的元数据信息,对象的哈希码,对象的GC分代年龄等信息.这些信息存放在对象头中

​ 这四个过程之后,代表虚拟机创建对象过程结束了,但是从Java 程序的视角来看,对象开刚刚开始 – init方法还没有执行,所有字段为零,所以程序员要开始执行init 方法,按照自己的意愿初始化

发布了22 篇原创文章 · 获赞 5 · 访问量 1051

猜你喜欢

转载自blog.csdn.net/lighter613/article/details/103629724