JVM虚拟机
实现跨平台的作用
1. JVM结构
JVM主要包括: 程序计数器(Program Counter)、Java堆(Heap)、Java虚拟机栈(Stack)、本地方法栈(Native Stack)、方法区(Method Area) 五大组成部分。
1.1 程序计数器(PC)(线程私有)
一个寄存器,可以看作是代码行号指示器,用于指示,跳转下一条需要执行的命令。Java的基础操作以及异常处理等都十分依赖PC。
JVM多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的。在一个确定的时刻,一个处理器(或者说多核处理器的一个内核)只会执行一条线程中的命令。因此,为了正常的切换线程,每个线程都会有一个独立的PC,各线程的PC不会互相影响。这个私有的PC所占的这块内存即是线程的“私有内存”。
如果线程在执行的是Java方法,那么PC记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的不是Java方法即Native方法,那么PC的值为undefined。
PC的内存区域是唯一的没有规定任何OutOfMemoryError的Java虚拟机规范中的区域。
1.2 Java虚拟机栈(Stack)(线程私有)
虚拟机栈是描述Java方法的内存模型,每个方法被执行时都会创建一个栈帧(Stack Frame)。栈帧会利用局部变量数组存储局部变量(Local Variables),操作栈(Operand Stack),方法出口(Return Value),**动态连接(Current Class Constant Pool Reference)**等信息。
生命周期和线程相同。
局部变量数组存储了八个基本类型(int、boolean、char、short、byte、long、float、double),和对象引用(根据不同的虚拟机实现可能是引用地址的指针或者一个handle),returnAddress类型。64位的long和double会占用两个Slot,其余类型会占用一个Slot。在编译期间,局部变量所需的空间就会完成分配,动态运行期间不会改变所需的空间。
对Java虚拟机栈这个区域,Java虚拟机规范规定了两种异常:
- 线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverFlow异常。
- 对于支持动态扩展的虚拟机,当扩展无法申请到足够的内存时会抛出OutOfMemory异常。
1.2.1 Jvm参数
1.3 本地方法栈(Native Stack)(线程私有)
执行的是Native方法,在JVM规范中,没有对它的实现做具体规定。
1.4 Java堆(Heap)(共享)
存放对象实例和数组,在虚拟机启动时创建。
Java堆是垃圾收集器管理的主要区域,也被称为CG堆。收集器采用的是分代回收法,有新生代,老生代。新生代又包括Eden Space和From Survivor Space、To Survivor Space。
根据Java虚拟机规范,堆所在的物理内存区间可以是不连续的,只要逻辑连续就可以。实现时既可以是固定大小,也可以是可扩展的。
对Java堆这个区域,Java虚拟机规范规定了一种异常:
- 如果堆无法扩展时,就会抛出OutOfMemory异常。
1.5 方法区(Method Area)(共享)
存放已经被虚拟机加载的类信息、常量(final)、静态变量(static)、静态代码块的区域,构造函数,常量池,接口初始化、即时编译器编译后的代码数据等。
这块区域的内存回收主要为常量池的回收和类型的卸载。这个区域的回收处理不善也会导致严重的内存泄漏。
对方法区这个区域,Java虚拟机规范规定了一种异常:
- 如果方法区无法满足内存分配需求时时,会抛出OutOfMemory异常。
Jvm虚拟机的常用命令
1、jps:查看本机java进程信息。
2、jstack:打印线程的栈信息,制作线程dump文件。
3、jmap:打印内存映射,制作堆dump文件
4、jstat:性能监控工具
5、jhat:内存分析工具
6、jconsole:简易的可视化控制台
7、jvisualvm:功能强大的控制台