揭开 java平台的神秘面纱 |
一个java程序员的水平高低最终取决于对 JVM (java虚拟机) 的了解程度 .
首先这篇文章带大家对 JVM 进行一个初步的了解 ,从下面两个问题进行解剖 。
1 . 什么是JVM ?
2 . JVM有什么用 ?
一 . 什么是 JVM ?
了解什么是JVM之前先简单说下什么是Java ?, 啥是Java很难用一句话来概括,我们从四个方面来阐述 .
语言 : 作为世界上最流行的编程语言,Java可以编写C/S、 B/S模式的软件。语法由Java Language Specification规定。
平台 : 作为一个开发平台,以JVM为基础,除Java外还有Groovy,Scala, Kotlin, JRuby,Clojure, Jython等语言。 虚拟机内部机制由Java Virtual Machine Specification规定。
文化 : 作为一种文化,Java几乎成为可“开源”的代名词.
生态 : 作为生态,Java拥有世界最多的技术拥护者和开源社区的支持。从桌面应用软件、嵌入式开发到企业级应用、后台服务、中间件都可以看到Java的身影.
大家学习 Java 的过程中,相信都会有了解到 JDK 和 JRE 这两个东西 , 我们要讲的 JVM 就属于 JRE当中的. 为什么叫做虚拟机呢 ? (如下图所示 : ) 因为 java 程序是在 java虚拟机中运行 ,通过JVM 来对 class文件进行翻译给操作系统执行 , 官方提供了不同操作系统上的 JVM . 在这里JVM相当于充当了翻译官的角色 , 也使java 有跨平台这个特性.[C语言、汇编语言等古老的语言不能跨平台] ,也对应了它的口号 “一次编译,到处执行”.
二 . JVM 有什么作用 ?
JVM 由 三个主要部件构成 :
① 类加载器 ② 运行时数据区 ③ 执行引擎
(1) 类加载器 [ClassLoader] :
它负责在运行时查找和装入类文件的类 , JVM里有多个类加载器 , 每个类加载器负责加载特定位置的类.(如下图:) 例如
引导类加载器(bootstrap) : 负责加载 jre/lib/rt.jar 中的类
扩展类加载器(extclassloader) : 负责加载 jre/lib/ext/*.jar 中的类
系统类加载器(appclassloader) : 负责 classspath 指定的目录或 jar 中的类
为什么要分成不同的类加载器呢? 主要为了安全性,打个比方如果一个有恶意class文件类并且路径伪装下,它要被加载的话首先会通过系统类加载器进行加载 ,加载器发现此类不符它的加载范围,会给它上一级扩展类加载器,因为每个加载器都有特定的加载范围,到最后这个类都不符合.就算在系统类加载器中加载了,也不会影响到JVM主要的类文件.
(2) 运行时数据区 [Runtime Data Area] :
Java虚拟机在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域.(如下图:)
主要分为五大区域块 :
方法区 (Method Area) : 这是一块公共区域 , 它存放一些加载后的类信息(有类的版本、字段、方法、接口等描述信息)、常量、静态变量等信息.
Java虚拟机规范规定,当方法区无法满足内存分配的需求时,将抛出 OutOfMemoryError 异常。
堆区 (Heap Area) : 堆也是被所有线程共享的一块区域,在JVM启动时创建 , 它存放对象实例,几乎所有的对象实例都在这里分配内存, 这块区域也是 GC(垃圾回收机制) 重点清理的区域 , 当堆中的内存无法分配给示例时,会抛出OutOfMemoryError异常。
虚拟机栈(VM Stack) : 它描述的是Java方法执行的内存模型 , 当执行一个方法时会创建一个栈帧 , 栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息 , 基本变量和对象的引用变量都存放于此.栈中执行顺序是 “后入先出(LIFO)” 这里打个比方:当一个Main方法调用另A方法,这时会创建两个栈帧先执行的Main方法会最后出这个栈,而A方法执行完后会先出栈,则A方法被销毁. 总的来说 一个方法的入栈出栈就表示着一个方法从调用到执行完成的过程 , 栈是线程私有的,它的生命周期与线程相同,Java虚拟机规范对这个区域规定了两种异常情况 :
①如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常
②如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常.(当前大部分JVM都可以动态扩展,只不过JVM规范也允许固定长度的虚拟机栈)
程序计数器(Program Counter Register) : 首先它是线程私有区域 , 它存储或说记录当前线程之前执行的任务状态,等线程抢到CPU时间片时,继续未完成的任务.[也称为PC寄存器]
本地方法栈(Native Method Stack) : 用于JNT调用等 ,.JNI技术,java调用c语言等其它语言开发的函数,本地方法栈中也会抛出StackOverflowError 和 OutOfMemory异常.该区域不受 GC 所管制.
[运行时数据区图:]
[方法区示意图:]
[虚拟机栈图:]
[栈帧出入示意图:]
(3) 执行引擎 [Runtime Data Area] : (如下图所示) 执行引擎 将字节码分配给运行时数据区 , 执行引擎读取字节码并逐段执行.其中图中的
本地接口 (JNI): JNI 会与本地方法库进行交互并提供执行引擎所需的本地库。
本地方法库:它是一个执行引擎所需的本地库的集合。
下面咱们来看一段代码:
public class Test1 {
public static int num = 1; //类变量会存放在方法区中
public void method1(){
/*
在这个方法中创建了一个对象,但是会在内存中产生两个相关数据.
我们知道等号左边的对象是等号右边的一个引用, 左边的引用是存放在
此方法栈帧中的,而右边的Test2则是一个实例对象,所以它存放在堆区中.
*/
Test2 test2 = new Test2();
}
}
相信看到这里大家对JVM有了一个初步的了解 , 在我们遇到的所有java问题都可以追溯到JVM中.今天的分享就到这里,后续还会继续更新相关内容,感谢大家 !
想了解 java GC机制的可看看 上一篇 博客内容 ==>> GC