Java虚拟机--对象的创建

下面简单说一下Java虚拟机中对象常见的原理:

我们编写代码肯定已经是很熟悉了,通过new关键字,给对象实例化并分配内存,但是实际上对象的创建是一步步很复杂的过程,我们先看一下对象创建的流程图。

在对象创建之前先要实现Java类的加载。虚拟机类加载机制我们之后会有详细讲解,这里就不详细展开了,而是将重点放在对象的创建方面。


我们看一下内存分配对象的几种方式

指针碰撞

我们首先假设堆内存是一段连续存放数据的区域,它分为两部分,空闲区域和使用区域,当对象创建之后分配内存时,空闲区域减少,使用区域增大,而堆中指向两部分区域分界的指针的移动则标志这创建对象锁占用的内存。

空闲列表

我们都知道,堆中的内存并不是我们想想的规规整整,实际上已使用的区域和空闲区域是杂错分配的,没有规律。这个时候我们创建对象是如何分配内存的呢。虚拟机中维护一张表,这个表存放并记录对内存中有哪些存储单元是可以使用的哪些是已使用的。当创建对象时,查询表中那些编号对应的存储单元是空闲区域,并找到空闲编码所对应的存储单元的地址。这样便可以为对象分配内存了。当然了,当创建对象成功分配内存之后,这张表也要做出及时的更新。

至于选择哪种内存分配方式,是由堆内存是否规整,而堆是否是规整的,又取决于虚拟机的垃圾回收策略决定的。如果垃圾回收机制中有对堆内存进行区域压缩的策略,将空闲区域和已使用区域进行压缩规整,那么我们就执行的指针碰撞策略。


对象创建的过程中可能会设计到线程安全的问题

通过上面的内存分配策略我们知道指针碰撞,当创建对象时会伴随指针的移动,然而在高并发的情况下,指针的移动很容易引起线程安全问题。当然在空闲列表的策略上也存在线程安全问题,比如在多线程并发的情况下,一个线程创建对象后空闲列表还没有及时更新,便有新的线程创建对象访问到同一个内存区域,这样是不是就引起了线程的安全性问题。

解决内存分配线程安全问题也是有解决方法的,首先从多线程的角度应该很容易的想到,我们可以给内存分配添加同步锁,当堆给一个对象分配内存时,不允许其他的线程访问堆内存。这不失为一种解决方法,只不过这种方式大大的降低了虚拟机堆内存分配的效率。

还有一种方法解决,本地线程分配缓冲。在堆内存中给每个线程单独分配一部分内存,这里每一小部分的内存大小可以在线程池中进行相关的参数配置。这样,就很难发生线程安全问题了,如果已经分配的内存不够,可以对该线程添加同步锁进行扩充内存。这种策略在性能方面有很大的改善。


初始化对象

在Java中对象创建之后会有一个默认的初始值。对象是那个类的实例,对象的哈希码等一系列的信息都存放在对象头中。其实在对象内存分配完成和初始化之后,对象的创建就差不多完成了,这里从开发者角度看,还是少了点东西的,那就是对象调用构造函数。

猜你喜欢

转载自blog.csdn.net/IBLiplus/article/details/82940407
今日推荐