浅谈JVM内存结构

浅谈JVM内存结构

(一)简述

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用户,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而创建和销毁。我们先来看一下JVM的内存分区:

在这里插入图片描述

PS:JDK 1.8 同 JDK 1.7 比,最大的差别就是:元数据区取代了永久代。元数据区的本质和永久代类似,都是对 JVM 规范中对方法区的实现。不过元数据区与永久代之间最大的区别在于:元数据空间并不在虚拟机中,而是使用本地内存。

(二)程序计数器

程序计数器是一块较小的内存空间,它可以看作是当前线程执行的字节码的行号指示器。
在虚拟机的概念模型,字节码解释器工作时,就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。

每条线程都有一个独立的程序计数器。为了线程切换后能恢复到正确的执行位置。java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式实现的,一个处理器(对于多核处理器来说就是一个内核)都只会执行一条线程中的指令。在多线程情况下,程序计数器记录的是当前线程执行的位置,从而当线程切换回来时,就知道上次线程执行到哪了。

(三)本地方法栈

本地方法栈是为 JVM 运行 Native 方法准备的空间,由于很多 Native 方法都是用 C 语言实现的,所以它通常又叫 C 栈。它与 Java 虚拟机栈实现的功能类似,只不过本地方法栈是描述本地方法运行过程的内存模型。本地方法被执行时,在本地方法栈也会创建一块栈帧,用于存放该方法的局部变量表、操作数栈、动态链接、方法出口信息等。

(四)java虚拟机栈

Java虚拟机栈是描述Java方法运行过程的内存模型。Java 虚拟机栈会为每一个即将运行的 Java 方法创建一块叫做“栈帧”的区域,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。一个方法对应一个栈帧。局部变量表存放了各种基本类型、对象引用和returnAddress类型(指向了一条字节码指令地址)。其中64位长度long和double占两个局部变量空间,其他只占一个。

在这里插入图片描述

当方法运行过程中需要创建局部变量时,就将局部变量的值存入栈帧中的局部变量表中。Java 虚拟机栈的栈顶的栈帧是当前正在执行的活动栈,也就是当前正在执行的方法,PC 寄存器也会指向这个地址。只有这个活动的栈帧的本地变量可以被操作数栈使用,当在这个栈帧中调用另一个方法,与之对应的栈帧又会被创建,新创建的栈帧压入栈顶,变为当前的活动栈帧。方法结束后,当前栈帧被移出,栈帧的返回值变成新的活动栈帧中操作数栈的一个操作数。如果没有返回值,那么新的活动栈帧中操作数栈的操作数没有变化。

由于Java虚拟机栈是与线程对应的,数据不是线程共享的,因此不用关心数据一致性问题,也不会存在同步锁的问题。

Java虚拟机栈规定的异常情况有两种:
1.线程请求的栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;
2.如果虚拟机可以动态扩展,如果扩展时无法申请到足够的内存,就抛出OutOfMemoryError异常。

(五)堆

Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建。

java堆的唯一目的就是存放对象实例对象。几乎所有的对象实例都在这里分配。这一点在java虚拟机规范中描述:所有的对象实例以及数组都要在堆上分配,但随着JIT编译器的发展与逃逸分析技术的成熟,所有的对象都分配在堆上也变的不是那样“绝对”了。

java堆是垃圾收集器管理的主要区域,因此很多地方也称为“GC堆”,从内存回收角度看,由于现在收集器基本都采用分代收集算法,java堆中还可以细分:新生代、老年代。新生代再细分可分为Eden空间、From Survivor空间、To Survivor空间。

当前主流的虚拟机的堆空间都是按照可扩展来实现的,通过(-Xmx和-Xms控制)。堆无法扩展时,抛出OutOfMemoryError异常。

(六)元数据区

在jdk1.8中,JVM移除了永久代,取而代之的是元数据区,也称为元空间(Metaspace) ,也就是将本地内存用来存储,容量取决于是32位或是64位操作系统的可用内存大小。元数据区是方法区的一种实现,这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间。当方法区无法满足内存分配需求时,抛出OutOfMemoryError异常。

元数据区是线程共享的。 整个虚拟机中只有一个元数据区。元数据区中的信息一般需要长期存在,回收一遍之后可能只有少量信息无效。因此内存回收效率低。主要回收目标是:对常量池的回收、对类型的卸载。Java虚拟机规范对方法区的要求比较宽松,和堆一样,允许固定大小,也允许动态扩展,还允许不实现垃圾回收。

2020年6月1日

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章