Java创建一个对象的过程

内容来自Thinking In Java

1、即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象时(构造器可以看成静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。

2、然后载入Dog.class(这将创建Class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。

3、当new Dog()创建对象的时候,首先在堆上为Dog对象分配足够的存储空间。

4、这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值(对数字来说是0,对布尔类型和字符类型也相同),而引用则被设置成了null。

5、执行所有出现于字段定义处的初始化动作。

6、执行构造器。但这会牵扯很多动作,尤其是涉及继承的时候。

参照《深入理解JAVA虚拟机》
(1)虚拟机遇到一个new指令时,做的事情有:

  • 检查这个指令的参数是否能在常量池中定位到一个类的符号引用
  • 检查这个符号引用代表的类是否已被加载、解析和初始化

(2)如果类没有加载,则JVM执行类的加载(加载过程详细见书本)

(3)为对象分配内存,对象所需的内存大小在类加载完成后就已经完全确定。分配内存有两种方法,主要取决于JAVA堆中的内存是否绝对规整;

  • JAVA堆绝对规整,采用“指针碰撞”分配方式
    JAVA堆中内存绝对规整,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离
  • JAVA堆中的内存并不是规整的,采用“空闲列表”分配方式
    如果JAVA堆中的内存不是规整的,已使用的内存和空闲的内存相互交错,虚拟机必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录

JAVA堆内存是否规整就要看垃圾收集器收否有压缩整理的功能

  • “指针碰撞”:Serial、ParNew
  • “空闲列表”:CMS

除了如何分配内存外(两种方法),还需要考虑的是对象的创建是否非常频繁,因为这涉及到线程安全不安全的问题,即使是简简单单的移动指针,如果线程不安全,在分配对象A和对象B的同时,就会出现问题。解决这个问题有两个解决方法:

  • 对分配内存空间动作进行同步处理
  • 把内存分配的动作按线程划分在不同的空间之中进行,也就是每个线程在JAVA堆中预先分配一小块内存,称为本地线程分配缓冲(TLAB),哪个线程需要分配内存,就在自己的那块TLAB上分配,只有自己的TLAB用完了,才会进行同步申请另一块内存。(JVM可以通过设定参数来决定是否需要TLAB)

(4)虚拟机需要将分配到的内存空间都初始化为零值(注意,这里不包括对象头)

(5)虚拟机对对象进行设置,将某些信息保存到对象头中,这些信息包括:

  • 这个对象属于哪个类的实例
  • 如果找到类的元数据信息
  • 对象的哈希吗(原来对象的哈希码保存到对象头)
  • 对象的GC分代年龄

(6)对该对象按照程序员的意思进行初始化(此时对象才真正产生出来)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值