深入理解Java虚拟机,学习记录<一>---虚拟机内存划分

85 阅读3分钟

java虚拟机的内存模型 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为以下几个区域

image.png

1.程序计数器

程序计数器可以看成当前线程所执行的字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。

由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,所有这块内存区域为“线程私有”的内存。

2.Java虚拟机栈

Java虚拟机栈也是线程私有的,它随着线程的销毁而销毁。

在方法被调用的时候,Java虚拟机会在虚拟机栈内同步创建一个栈帧用来存储方法的局部变量表、操作数栈、动态连接、方法出口等信息。当方法调用完毕后,栈帧会在虚拟机栈中弹出。

局部变量表所需的内存空间在编译期间完成分配,单位是槽。其中64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占用一个。

当栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果Java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛OutOfMemoryError异常。(Java使用的HotSpot虚拟机的栈容量是不可以动态扩展的,在线程申请栈空间成功的情况下是不会出现OutOfMemoryError异常)

3.本地方法栈

本地方法栈与虚拟机栈的区别是:虚拟机栈为虚拟机执行Java方法服务,本地方法栈则是为了虚拟机使用本地方法服务。在HotSpot虚拟机中,把本地方法栈和虚拟机栈合二为一。

4.Java堆

Java堆被所有线程共享,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。

Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。可以通过-Xmx和-Xms参数设定堆的最大内存大小、内存大小。

5.方法区

方法区和Java堆一样,被各个线程共享,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

在JDK8之前使用使用永久代来实现方法区。JDK7的HotSpot虚拟机把原本放在永久代的字符串常量池、静态变量等移出。到了JDK8时完全废弃了永久代的概念,使用在本地内存实现的元空间来代替,把JDK 7中永久代还剩余的内容(主要是类型信息)全部移到元空间中。

运行时常量池是方法区的一部分。Class文件中的常量池表(用于存放编译期生成的各种字面量与符号引用)在类加载后存放到方法区的运行时常量池中。当常量池无法再申请到内存时会抛出OutOfMemoryError异常。