一分钟扫盲:Java虚拟机运行时数据区

一分钟扫盲:Java虚拟机运行时数据区

 

Java虚拟机所管理的内存将会包括以下5个运行时数据区域:

  • 方法区

  • 虚拟机栈

  • 本地方法栈

  • 程序计数器

线程私有:每个线程都会有自己独立的空间,随线程的生命周期而创建和销毁。

线程共享:所有线程都能访问到的内存空间,随虚拟机或GC而创建和销毁。

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

  • 是什么:

    一块较小的内存空间,可看做当前线程所执行的字节码的行号指示器。

  • 是否线程私有:

  • 存什么:

    • 如果线程正在执行的是Java方法,那么计数器记录的正在执行的虚拟机字节码指令的地址;

    • 如果线程正在执行的是Native方法,那么计数器值则为空(Undefined)。

  • 异常:唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError。

    为什么说不会出现OutOfMemoryError?首先我们得知道什么原因才会出现OutOfMemoryError,只有需要申请增加内存,但系统以及没有多余的内存的时候,才会出现内存溢出错误。程序计数器它只是存了个线程执行的字节码指令地址而已,并不会重新申请更多的内存,就不会出现内存溢出。

     

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

  • 是什么:

    虚拟机栈描述的是Java方法执行的内存模型,每个方法从调用直至执行完成的过程,就对应这一个栈帧在虚拟机栈中入栈到出栈的过程。

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

    局部变量表:存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和returnAddress类型(指向了一条字节码指令的地址)

  • 是否线程私有:

  • 存什么:栈帧

  • 异常: StackOverflowError、OutOfMemoryError

    • StackOverflowError:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出异常。

    • OutOfMemoryError:如果虚拟机栈可以动态扩展(当前大部分Java虚拟机都可动态扩展,只不过Java虚拟机规范也允许固定长度的虚拟机栈),如果扩展时无法申请到足够的内存,就会抛出异常。

 

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

  • 是什么:

    本地方法栈为虚拟机使用到的Native方法服务。

    跟Java虚拟机栈非常相似,只不过Java虚拟机栈是为虚拟机执行Java方法(也就是字节码)服务

  • 是否线程私有:

  • 存什么: 栈帧

  • 异常: StackOverflowError、OutOfMemoryError

 

4. Java堆(Java Heap):

  • 是什么:

    • 唯一的目的是存放对象实例,几乎所有的对象实例都在这里分配内存。

    • Java虚拟机所管理的内存中最大的一块。

    • 被所有线程共享,在虚拟机启动是创建。

  • 是否线程私有:

  • 存什么: 对象实例

  • 异常: OutOfMemoryError

     

5. 方法区(Method Area):

  • 是什么:

    虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。

  • 是否线程私有:

  • 存什么: 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

  • 异常: OutOfMemoryError

 

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

  • 是什么:

    运行时常量池是方法区的一部分。

  • 是否线程私有:

  • 存什么: 编译期生成的各种字面量和符号引用,这部分将在类加载后进入方法区的运行时常量池中存放。

  • 异常: OutOfMemoryError

 

参考:《深入理解Java虚拟机》

 

一分钟扫盲:Java虚拟机运行时数据区