1 基本概念 1.1 JVM概念
JVM(Java Virtual Machine)是用来执行Java代码的虚拟机。 JVM 可以直接运行在不同的操作系统上。 Java代码经过编译器编译生成.class字节码文件,字节码文件通过JVM中的解释器编译成可以直接运行的机器码,这就是Java可以实现跨平台的原因。
1.2 JVM的位置
JVM 直接运行在操作系统上,不直接与系统硬件交互。
JVM 的位置
1.3 操作过程
Java源文件通过编译器编译成字节码文件,字节码文件通过JVM编译成相应平台可以直接执行的机器码。 当一个程序开始运行时,会启动一个对应的Java虚拟机实例来支持该程序的运行。 当多个程序运行时,会启动多个Java虚拟机实例。 Java 虚拟机实例将随着程序的退出或关闭而消亡。 同时,多个Java虚拟机实例之间的数据是不共享的。
1.4 运行时数据区
运行时数据区
运行时数据区中的内存区主要分为线程共享区和线程私有区。 这里的线程指的是Java程序中的线程。 Java程序中允许一个程序有多个线程,线程共享区在整个JVM中。 运行时最初只会创建一份,随着JVM的启动而创建。 多个线程会共享这个区域的数据,当前区域也会发生垃圾回收。 用线程创建一个副本,并在线程结束时销毁它。 每个线程只能访问自己私有区域的数据。
1.4.1 程序计数器
在Java中,当一个Java源代码文件被编译成字节码时,就形成了一行字节码指令,而程序计数器(Program Counter Register)主要保存的是当前线程执行的字节码。 行号,字节码解释器通过改变程序计数器中存储的行号获得下一条要执行的字节码指令。
在任何给定的时间,一个处理器(对于多核处理器来说就是一个核)在一个线程中只会执行一条指令,所以程序计数器的主要作用是保证程序计数器在多线程环境下执行。 可以恢复到正确的执行位置。 比如当前程序中有两个线程A和B。 当线程A执行到第3行的指令时,程序计数器就存储了第3行,此时CPU被分配去执行线程B,执行完线程B的指令后java基础代码,再次切换到线程A。 这时,程序计数器中保存的行号可以立即恢复到需要继续的位置。
1.4.2 Java虚拟机栈
Java虚拟机栈(Java Virtual Machine Stacks)是程序运行中最重要的部分。 对应的Java方法执行的内存模型,当一个Java方法执行时,会创建一个对应的栈帧(Stack Frame),栈帧主保存的信息包括局部变量表(八种基本数据类型(boolean, byte, char ,short,int,float,long,double),对象引用,returnAddress类型),操作数栈,动态链接和方法退出等,一个Java方法从被调用到执行结束对应的过程是压入和弹出一个栈帧,程序当前执行的方法必须在栈顶。
栈帧
比如一个应用程序中有方法A和方法B,在方法A中调用了方法B,那么方法A执行时会产生一个栈帧,方法A对应的栈帧会被压入virtual机器栈,在方法A中调用方法B时,会生成一个方法B对应的栈帧,压入虚拟机栈。 此时方法B对应的栈帧在虚拟机栈顶。 当方法B执行完成后,栈帧会被弹出,然后方法A对应的栈帧会成为顶层栈帧,程序会继续执行方法A。当方法A执行完毕后,会弹出方法A对应的栈帧,执行当前程序。
1.4.3 Native方法栈
本地方法栈(Native Method Stack)和虚拟机栈起到的作用非常相似。 它们的区别在于,虚拟机栈是为虚拟机执行Java方法(也就是字节码)服务的,而native方法栈是为虚拟机使用的Native方法服务的。
1.4.4 Java堆
Java堆(Java Heap)是Java虚拟机中最大的一块内存。 该区域的主要功能是存放对象实例。 当一个对象被实例化时,它被存储在堆空间中。 几乎所有的对象实例都在堆空间中分配内存。
堆空间也是垃圾收集(Garbage Collection)的主要区域。 同时,由于当前收集器基本采用分代收集算法,因此Java堆也细分为新生代、老年代、永久代(JDK8后,永久代改为新生代,又分为Eden区、From Survivor区和To Survivor区。
堆
1.4.5 方法区
方法区主要用于存放Java虚拟机加载的类信息、运行时常量池、静态变量、编译代码等数据。 同时,方法区还有一个别名:非堆(Non-Heap)。 方法区是JVM规范的逻辑部分,也就是说,方法区不是具体的实现java基础代码,而是一种规范。 永久代只是针对方法区的具体实现,但只存在于jdk7之前的版本,在jdk8以后的版本中,永久代被移除,取而代之的是Metaspace。 同时,并不是所有的 JVM 都有永久代。 IBM 的 j9 和 Oracle 的 JRocket 没有永久代。
方法区是一个规范,规定了这个区域可以存放什么数据。 永久代和元空间是方法区的不同具体实现。