JVM对象的创建和内存分配

注:本文摘自  https://www.cnblogs.com/ming-zi/p/6670351.html


一、对象的创建

     当虚拟机接受到new指令时,会去常量池检查是否有new指令中包含的参数(例如:new People(); jvm首先检查常量池中是否有People这个类的符号引用),并且检查这个类是否被加载了,如果没有会执行类加载过程。

      在类加载检查过后,会在堆内存中为这个对象实例分配内存,内存分配之后虚拟机需要将每个对象分配到的内存初始化为0值(不包括对象头)。

        接下来虚拟机对对象进行必要的设置,如对象属于哪个类的实例,如何找到类的元数据信息,对象的Hash码,对象的GC年代信息等,这些信息会被放在对象头里。

        执行完上面工作之后,所有的字段都为0,接着执行<init>指令,把对象按照程序员的指令进行初始化,这样一个对象就完整的创建出来。

    另外 ,在为对象分配内存时还有3个问题需要注意

      a、给对象分配多大的内存

      对象所需的内存大小在类加载的过程中会确定下来

      b、给对象分配内存有2种方式

       为对象分配内存根据堆内存是否规整分为2种方式(堆内存是否规整和垃圾回收器是否有带有压缩整理功能有关):

     1. 指针碰撞(Bump the Pointer)和2。 空闲列表(Free List)

        指针碰撞:如果java堆是规整的,即所有用过的内存放在一边,没有用过的内存放在另外一边,并且有一个指针指向分界点,在需要为新生对象分配内存的时候,只需要移动指针画出一块内存分配和新生对象即可;空闲列表:当java堆不是规整的,意思就是使用的内存和空闲内存交错在一起,这时候需要一张列表来记录哪些内存可使用,在需要为新生对象分配内存的时候,在这个列表中寻找一块大小合适的内存分配给它即可。

       c、 新生对象分配内存的时候,同时还需要考虑线程安全问题

       因为在并发的情况下内存分配并不是线程安全的。有两种方案解决这个线程安全问题,1、为分配内存空间的动作进行同步处理;2、为每个线程预先分配一小块内存,称为本地线程分配缓存(Thread Local Allocation Buffer, TLAB),哪个线程需要分配内存,就在哪个线程的TLAB上分配。


二、对象的内存布局 

  

 对象在内存的存储布局中包括:对象头、实例数据、对齐填充

  对象头(Header):包含两部分信息。1、存储对象自身的运行时数据,比如哈希码、GC分代年龄等;2、类型指针:通过这个指针确定这个对象属于哪个类。

  实例数据(Instance Data):存储代码中定义的各种类型的字段内容。

  对齐填充(Padding):这部分信息没有任何意义,仅仅是为了使得对象占的内存大小为8字节的整数倍。

三、对象的访问定位

创建对象是为了使用对象,java程序需要通过栈上的reference数据来操作栈上的具体对象。目前主流的访问对象方式有使用句柄和直接指针两种。1、使用句柄方式:会在java堆中创建一个句柄池,reference指向的这块句柄池,句柄池中包括两个指针,其中一个指针指向对象实例数据,另外一个指针指向对象的类型数据。2、使用指针的方式:reference存储的直接就是对象的地址。

  两种方式各有各的特点,如果使用句柄方式的话,最大的好处是reference存放的是稳定的句柄地址,在对象移动时只会改变句柄中的实例数据指针,而reference本身不需要修改。使用指针的方式优势则是速度快,并且省去了一次指针定位的开销。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值