JVM(一)
Java 环境
Java 运行过程
下面几张图,我们可以了解到 Java 这门语言是如何进行运行的。
java文件通过编译器编译成class文件,然后在虚拟机中转化为机器语言运行在机器上。
上图展示了java 在不同平台的实现。下图则是大意视图。
JDK 和 JRE
JVM:Java Virtual Machine(Java虚拟机),负责执行符合规范的Class文件
JRE:Java Runtime Environment(java运行环境),包含JVM和类库
JDK:Java Development Kit(java开发工具包),包含JRE和开发工具包,例如javac、javah
从这张图可以看到JDK 可以由 JRE 和 工具类及工具API 组成。而JRE 则是 Java SE API 加上底层的虚拟机。
运行时数据区域
概述
java虚拟机在这行java程序的过程汇总会把它所管理的内存划分为若干个不同的数据区域,各区域各有御用,以及创建和销毁的的时间,下图是虚拟机管理的内存区域。
图一 按功能区域划分,注意了线程共享和隔离的区域
图二 各线程真实地持有各部分的内存空间
图三 JVM栈
我们可以看到线程共享有 堆和方法区,而JVM 栈中包含本地变量数组,操作数栈,常量池引用。
程序计数器(Program Counter Register)
PC Register可以看成是当前线程所执行的字节码的行号指示器,字节码解释器工作时都是通过这个计数器来选择下一条需要执行的字节码指令。同时当线程切换时,程序计数器纪录当前执行的指令,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”内存。
- 正在执行Native 方法,计数器数值为 0
- 次内存区域是唯一一个在Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域
虚拟机栈 (JVM Stacks)
线程私有,与线程的生命周期一样,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,存放了编译器可知的各种基本数据类型(boolean ,byte,char,short,int,float,long,double),对象引用(reference 类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress 类型(指向了一条字节码指令的地址),这个区域规定了两种异常:
- StackOverFlowError : 栈深度超过允许深度
- OutOfMemoryError
本地方法栈 (Native Method Stack)
JVM Stack为虚拟机执行 java 方法,而本地方法栈则是为虚拟机所使用到的 Native 方法服务。有些虚拟机将这两个栈合并在一起
java 堆:
java堆是被所有线程共享的一块内存区域,几乎所有的对象实例都在这里分配内存,这区域也是垃圾收集器管理的主要区域,因此很多时候被称作“GC堆”--(GarbageCollected Heap)。从内存回收角度来看,由于现在收集器基本都采用分代收集算法,所以java堆中还可以细分为 : 新生代和老生代。
方法区(Method Area)
方法区和java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。它还有一个别名--“Non-Heap(非堆)”。
运行时常量池(Running Constant Pool)
是方法区的一部分,Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译器生成的各种字面量和符号引用。
直接内存(Direct Memory)
直接内存并不是虚拟机运行时的数据区的一部分,也不是java虚拟机规范中定义的内存区域,但这部分也被频繁使用。特点就是 : 分配在堆外。
上面的图片提到的 DirectByteBuffer 就是直接内存的运用。