Skip to content

Latest commit

 

History

History
110 lines (55 loc) · 4.79 KB

Java内存区域划分.md

File metadata and controls

110 lines (55 loc) · 4.79 KB

Java内存区域划分

运行时数据区域:

线程隔离的数据区

  1. 程序计数器(Program Counter Register):

    程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.
    由于Java虚拟机的多线程是通过线程轮流转换并分配处理器执行时间的方式来实现的,所以每条线程都需要有一个独立的程序计数器.

  2. Java虚拟机栈(Java Virtual Machine Stacks):

    线程私有,生命周期与线程相同.

    • 描述Java方法执行的内存模型:

      每个方法执行时都会创建一个栈帧,用于存放局部变量表,操作数栈,动态链接,方法出口等.
      每个方法从调用到完成,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程.

  3. 本地方法栈(Native Method Stack):

    本地方法栈Java虚拟机栈类似,不过它是服务于虚拟机用到的Native方法.
    有的虚拟机将本地方法栈虚拟机栈合二为一(Sun HotSpot).

    什么是Native方法?
    Native方法就是一个非java语言实现的方法


所有线程共享的数据区

  1. Java堆(Java Heap):

    Java堆是被所有线程共享的一块用于存放对象实例的内存区域,在虚拟机启动时创建.一般情况下,所有的对象实例数组都要在堆上分配.

    从垃圾回收的角度: 可以分为新生代老年代
    从内存分配的角度: 线程共享的堆可以划分出多个线程私有分配缓冲区(TLAB).

  2. 方法区(Method Area):

    用于存储已被虚拟机加载的类信息,常量(final),静态变量(static),即时编译器编译后的代码等数据.
    这个区域的垃圾回收比较少,但并不是没有(主要针对常量池的回收类型的卸载).

    • 运行时常量池(Runtime Constant Pool):

      常量池(Constant Pool Table): Class文件中的一项描述信息,用于存放编译器生成的各种字面量符号引用.

      运行时常量池方法区的一部分.Class文件中的常量池信息会在类加载后存放在运行时常量池中.

注意: 在虚拟机规范中,方法区的一个逻辑部分,故Java堆方法区同属于广义上的.


虚拟机对象(HotSpot):

对象的创建过程:

注: 只针对普通Java对象,不包括数组和Class对象等.

  1. 虚拟机遇到new指令时会检查这个指令的参数能否在常量池中定位到一个类的符号引用

  2. 检查引用代表的类是否执行类加载过程(被加载,解析初始化过),若没有就执行相应过程.

  3. 类加载检查通过后,虚拟机就为新生对象分配空间.

  • 并发情况下的线程安全解决方案:

    1. 对分配内存空间的动作进行同步处理.

    2. 哪个线程需要分配内存,就在自己的本地内存分配缓冲(TLAB)上分配.TLAB用完后才会同步锁定分配新的TLAB.

  1. 分配完成之后,虚拟机将分配到的内存空间(包括实例属性)初始化为零值(可提前在TLAB分配时进行).

  2. 执行<init>方法,按程序员的意愿初始化.

对象的内存布局:

对象在内存中可分为三个区域: 对象头(Header),示例数据(Instance Data)对齐补充(Padding).

  1. 对象头:

    对象头包含两部分信息:

    1. Mark Word: 用于存放对象自身的运行时数据(哈希码,GC分代年龄,锁状态标志,线程持有的锁...).
    2. 类型指针: 指向该对象的元数据类型(应该是Class对象)的指针,虚拟机通过它来确定这个对象是哪个类的实例.(若是数组还有一块用于几率数组长度)
  2. 示例数据:

    对象真正存储的有效信息,也是程序代码中定义的各种类型的字段内容.无论是子类中定义的还是从父类继承的,都要记录起来.

  3. 对齐填充:

    对象的大小必须为8字节的整数倍,没有的话需要进行对齐填充来补全(类似空格占位).

对象的访问定位:

Java程序通过栈上的reference引用来指向堆上的具体对象.

  • 对象引用的定位方式:
  1. 句柄访问: Java堆上划分出一块内存作为句柄池,reference中储存的是对象的句柄地址.而句柄中包含了对象实例数据地址对象类型数据地址.

    优点: reference中储存的是稳定的句柄地址,在对象移动时(垃圾收集时移动很普遍)只会改变句柄池中的实例数据指针,reference本身不用修改.

  2. 直接指针访问: reference中储存对象地址.而对象地址中包含了对象实例数据对象类型数据地址.

    优点: 速度更快,节省了一次指针定位的开销.