对象的创建过程:
我们在Java代码中new 一个对象时,我们很难看到对象创建的过程,尤其是在jvm内存中的过程,下面来介绍一下对象创建在jvm中的过程:
对象实例在jvm中是存在于java堆中的,每一个对象实例都会占用一定的内存空间,
当new执行时,首先会加载new的类
当类加载完成之后,实例对象所占的大小就确定了。
此时,jvm会在java堆中为实例对象开辟一块内存空间,用于存储对象实例。并且设置对象属于哪个类、如何找到对象(指针或地址)、对象的哈希码、对象的GC分代年龄等信息,这些信息存储在对象头中,还进行了对象属性的零值初始化。
此时对于虚拟机来说已经完成了创建对象,但是对于java程序来说才好刚刚开始,对象初始化的init方法还没有执行。但是此时虚拟机已经进行了对象得零值设置,所以即使不执行init方法,程序中也是可以正常是用对象实例的。
实例化对象过程中的注意事项以及方法:
jvm为实例对象分配空间主要有两种方法
一:指针碰撞:这种方法是在java堆中,将已用内存和未用的内存分开成两部分,两部分内存之间放这一个指针作为分界点,当有新的实例对象需要分配内存空间时,指针向未用内存一侧移动相应大小的距离,将新的实例对象存储在该内存空间上。这种方式需要内存是规整的。
二:空闲列表:这种方法分配空间是随机,每次分配内存空间都是从空闲的内存中选取一块分配给实例对象。那么就需要一个列表来存放这些空闲的内存空间地址,每当有实例对象需要空间,就从这个列表中选取出一块内存分配给实例对象。这种情况下内存是不规则的。
两种方法的选择取决于内存的结构是否规整,而内存结构是否规整则取决于采用的垃圾回收器是否带有压缩整理功能。
例如:Serial、ParNew等带有compact过程的收集器,就是带有压缩整理功能的
CMS这种基于Mark—Sweep算法的收集器就是没有压缩整理功能的
有些时候,创建对象操作很频繁,这样就有可能导致指针刚刚分配好,还没来得及创建对象,就被另一个线程抢先,先占用了指针,这时候就会产生问题,解决这种问题主要有两种办法:
一:对创建对象动作行为进行同步处理,这种同步处理实质是CAS配上失败重试的方式实现保证更新操作的原子性的。
二:把每一个创建对象的动作行为按照线程划分为不同的空间中进行,这种方式就是将创建对象行为放入到线程中,为每一个线程分配一小块内存空间(TLAB),每个线程要分配内存就在自己的TLAB上运行分配,只有当TLAB满了,需要重新分配TLAB时,才需要进行同步锁定。
TLAB方式的开启需要通过-XX:+/-UseTLAB参数设定。
猜你喜欢
静态const保留字,是一个类型修饰符,使用const声明的对象不能更新。与final某些类似。
2019-01-16
跳转goto保留关键字,但无任何作用。结构化程序设计完全不需要goto语句即可完成各种流程,而goto语句的使用往往会使程序的可读性降低,所以Java不允许goto跳转。
2019-01-16
无返回值void关键字表示null类型。void可以用作方法的返回类型,以指示该方法不返回值。
2019-01-16
本类this关键字用于引用当前实例。当引用可能不明确时,可以使用this关键字来引用当前的实例。
2019-01-16
父类,超类super关键字用于引用使用该关键字的类的超类。作为独立语句出现的super表示调用超类的构造方法。super.()表示调用超类的
2019-01-16