深入理解JVM(一)Java内存区域

运行时数据区

jvm数据区

  • 程序计数器

    当前线程执行的字节码的行号指示器

    每条线程都有独立的程序计数器,各线程之间计数器互不影响,独立存储。

    如果执行的是java方法,计数器记录正在执行的虚拟机字节码指令的位置;

    如果执行的是native方法,计数器值为空(undefined)

  • 虚拟机栈

    每个方法在执行的同时会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出入口等信息。

    一个方法从调用到执行完成就对应栈帧从入栈到出栈。

    两种异常:

    1. 线程请求栈深度大于虚拟机允许的最大深度,StackOverFlowError
    2. 如果虚拟机允许栈动态拓展,且在拓展时无法申请到足够内存,抛出OutOfMemoryError
  • 唯一目的,存放对象实例,也称为GC堆

    是GC管理的主要区域

  • 方法区

    存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据

    方法区是JVM的一种规范,落地可能是不同的实现

    PermGen space 是 JDK7及之前, HotSpot 虚拟机 对 方法区 的一个落地实现。在JDK8被移除。

    Metaspace(元空间)是 JDK8及之后, HotSpot 虚拟机 对 方法区 的新的实现。

    元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存

    当方法区无法满足内存分配要求,抛出OutOfMemoryError

对象初始化过程

对象初始化

对象的内存布局

对象在内存中存储的布局可以分为三块区域:对象头(Header),实例数据(Instance Data),对齐填充(Padding)

  • 对象头

    长度一般为32位或者64位,分为两部分信息:一部分用于存储对象自身的运行时数据,如哈希码,GC分代年龄,锁状态标志,线程持有的锁,偏向线程的ID,偏向时间戳等,称之为Mark Word。另一部分是类型指针,是对象指向他的类元数据的指针,用于确定是哪个类的实例(非必须);如果是数组还需要有一块记录数组长度的数据

  • 实例数据

    在程序代码中定义的各种类型的字段内容,无论是继承的还是自己的。

  • 对齐填充

    非必须,内存管理系统要求对象起始地址必须是8字节的整数倍,通常用于填充实例数据。

对象的访问方式

java程序通过栈上的reference数据来操作对象。常用的有两种,使用句柄直接指针

  • 使用句柄

    java堆中划出一块用于存储句柄(句柄池),reference存储的就是句柄地址

    img

    好处是当对象被移动时只需要修改句柄中实例数据地址

  • 使用指针

    reference存储对象地址,对象存在在堆中同时需要存储到对象类型的指针和对象实例数据

    好处是减少了一次指针定位的开销,Sun HotPot是以这种方式访问的

    img

原文地址:https://www.cnblogs.com/CodingJacob/p/13099696.html