JVM的组成
JVM 由类加载器子系统、运行时数据区、执行引擎以及本地方法接口组成。
JVM 的工作过程
类加载机制
关于类加载机制,前面已经做过介绍,这里就不再进行介绍了。
详情请见:类加载机制
Java内存模型
JVM内存划分:
- 方法区(线程共享):常量、静态变量、JIT(即时编译器)编译后的代码也在方法区存放。
- 堆内存(线程共享):垃圾回收的主要场地。
- 程序计数器:当前线程执行的字节码的位置提示器。
- Java虚拟机栈(栈内存):保存局部变量,基本数据类型以及堆内存中对象的引用变量。
- 本地方法栈(C栈):为JVM提供使用native方法的服务。
内存模型介绍:(功能、是否线程共享、生命周期、抛出的异常)
1、程序计数器
程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线性恢复等功能都需要依赖这个计数器来完成。另外,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
主要作用有两个:
- 1、字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
- 2、在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪而了。
注意:程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。
2、Java虚拟机栈
与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期和线程相同,描述的是Java方法执行的内存模型。
Java内存可以粗糙的区分为堆内存(Heap)和栈内存(Stack),其中栈就是现在说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。(实际上,Java虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。)
局部变量表:
主要存放了编译器可知的各种数据类型(boolean\byte\char\short\int\float\long\double)、对象引用(reference类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。
Java虚拟机栈会出现两种异常:StackOverFlowError 和 OutOfMemoryError。
- StackOverFlowError:若Java虚拟机栈的内存大小不允许动态扩展,当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就会抛出 StackOverFlowError 异常。
- OutOfMemoryError:若Java虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出 OutOfMemoryError 异常。
Java虚拟机栈也是线程私有的,每个线程都有各自的Java虚拟机栈,而且随着线程的创建而创建,随着线程