• 第十四篇 JVM之运行时数据区<10>: 对象分配过程


    一、对象的访问定位

    堆中存对象,栈上存引用,JVM中有两种对象访问定位方式:

    1、通过直接引用访问

     如图,直接引用方式是局部变量存储是对象实例的地址,同时,对象所属的类也可以通过对象实例获取。

    2、通过句柄池访问

      如图,句柄访问方式是在堆中开辟了一块句柄池,句柄池存储了对象的引用和所属类的引用,而局部变量表存储了句柄池的地址。

    • 对比:

      句柄方式,当对象位置发改变时(如GC时,对象复制),不需要改变局部变量的引用。访问对象的类型数据时,可以直接获取,而不用获取对象实例之后再访问。
    直接引用,可以直接通过引用获取到对象实例,速度更快,HotSpot虚拟机采用该方式。


    二、对象的内存布局

    对象在堆中的内存布局主要分为三个部分:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。

    1、对象头

    • Mark Word: 存储对象自身运行时的数据,主要内容如下表
    • 类型指针:指向对象所属类的类型数据。
    • 数组长度:档案实例是一个Java数组时,对象头中用于记录数组长度的区域。

    2、实例数据

      对象存储的真正有效信息,各种字段内容,包括从父类继承的。

    3、对象填充

      没有实际意义,相当于占位符,如果对象实例所占空间不是8字节的整数倍,就通过对齐填充补充到8的整数倍(HotSpot虚拟机的自动内存管理系统要求对象的起始地址必须是8的整数倍)


    三、堆中的线程私有区域

      

     

      堆中的区域并不是都是线程共享,为提高对象分配的效率,线程在堆中划分出了线程私有的分配缓冲区(Thread Local Allocation Buffer,简称TLAB)。默认情况下,TLAB仅占Eden区的1%,可以通过-XX:+UseTLAB启用TLAB,也可以通过-XX:TLABSize调节TLAB的大小。

    • TLAB的优势:
    • 提高分配效率,堆区作为共享区域,Eden区对象创建频繁,给对象分配内存时,为保证线程安全,避免多线程操作同一地址,必然需要一系统加锁机制,进而影响分配速度。TLAB是对象分配的首选区域,在TLAB中给对象分配内存失败时,才会在Eden区分配。

    四、对象创建过程

    对象创建过程:

    1、当JVM执行到一条new指令时(如new #2 <heap/HeapPartDemo>),就会去根据符号引用(#2)检测运行时常量池中这个符号引用指向的类是否已经完成加载、解析和初始化。如果没有就会进行该类的类加载过程。

    2、当检测到类已加载,就会开始分配内存,对象的大小在类加载阶段就已确定,在Java堆中为对象分配内存有指针碰撞和空闲列表两种方式,对象根据条件不一定分配在Eden区,这个栈上分配时再写。

    • 指针碰撞(Bump The Pointer):如果Java堆中内存是规整的,已用内存区域和空闲内存区域用一个指针作为分界线,在分配内存给对象时,只要依据对象所需内存(对象大小在类加载时就会确定),将指针向空闲内存区域移动一段与对象大小相等距离即可,如Eden区内存区域是[0x00000000fd580000,0x00000000ff600000],,0x00000000fd969620是指针位置,分配时在,0x00000000fd969620基础上加上对象大小即可,0x00000000fd969620就是对象的起始地址,依据对象填充,这个地址换算过来应该是8的整数倍。
    • 空间列表(Free List):如果Java堆中内存不规整,已用内存和空间内存交织在一起,就需要有一个表记录那些内存可用,这个表就被称为空闲列表,给对象分配内存就需要从空闲列表中找到一块足够的区域分配内存,同时更新表信息。

    同样,对象分配内存也存在并发问题,对象分配内存线程问题的解决方式:

    • 采用CAS配上失败重试的方式使得线程同步。
    • 线程私有的分配缓冲区TLAB。

    3、完成内存分配之后,就会进行对象实例数据属性初始化,这一步保证了即使对象字段属性即使没有赋值,也能被使用,访问到对应的零值。

    4、实例数据初始化完成后,需要设置对象头,包括Mark Word、类型指针和数组长度。

    5、执行Class文件里<init>()方法,完成Java程序意义上的对象构造函数。

  • 相关阅读:
    Stanford NLP 课程笔记之计算字符串距离
    Stanford NLP 课堂笔记之正则表达式
    最长回文子串
    java面向对象
    java中数组的定义
    AtCoder Beginner Contest 100 C(思维)
    Codeforces 1000B Light It Up(思维)
    jq的链式调用.end();
    解决css中display:inline-block的兼容问题
    解决css中display:inline-block产生的空隙问题
  • 原文地址:https://www.cnblogs.com/zhexuejun/p/15708872.html
Copyright © 2020-2023  润新知