第一个月将JAVA SE的基本语法学全,对JVM有了一点了解,先写下来,算是对知识的巩固,待来日有了新的见解或者有大神看到提出,再来更正。以下内容,都是小可一点拙见,不保证正确,如有错误,欢迎大佬指正,感激不尽!
1 常与之对比的概念:
JDK , java development kit,即java开发的全工具包包括JRE
JRE, java runtime evironment,即java运行环境,包含在JDK中
JVM , Java Virtual Machine,即java虚拟机,java程序运行的平台
2 JVM的作用
java语言必须在JVM中运行,而java最重要的优点之一跨平台性也是通过JVM体现出来的,即只要java语言编译后得到的.class文件,在不同的操作系统平台上都可以通过各自的JVM运行起来。
3 JVM如何作用
java程序从.class文件经过类加载器加载,到Runtime Data Area(运行时数据区),中间会有执行引擎,而执行引擎主要由GC和JIT即时编译器组成。
重点需要了解的为Runtime Data Area。
运行时数据区主要由堆,栈,方法区和栈构成,其中堆主要保存类的实例化对象以及数组,而方法区保存的是静态变量,静态方法和类的基本信息,方法区和堆都是线程共享的。
而栈和程序计数器是线程私有,其中栈由栈帧构成,栈帧遵循先进后出的原则(FILO),所以main方法最先进最后出,栈中保存的是对象的引用地址以及栈操作和基本数据类型。程序计数器则是用来标记每一个线程调用的。
用例子来说明JVM的构成,如果把java程序看做一个巨大的工程,那么堆空间就是仓库,放各种建材,仓库是共有的,每个工地都可以去拿,方法区则是工程说明文档,存放着各种工程应该怎么做之类,也是共有的。而栈则相当于工程师和工人,只负责自己的一块工地(线程),处理每一个线程(工地),是私有的,而程序计数器就是工程进度表,记录每一个线程即进度点,因此也是私有的。
需要注意的点:
1 线程私有和线程共有
2 常量池的特殊性,常量池在JDK1.7后移入堆中,常量池中储存的是常量,只要值相同即统一享有一个地址,但如果使用new方法还在堆空间中实例化了一个对象则引用指向的是堆空间的实例对象。
3 栈中除了虚拟机栈还有本地机栈,本地机栈主要是针对C语言的程序接口
2019.9.17补充
JAVA文件编译过程如图所示,从JAVA文件到机器码,字节码文件为中间态,其中JIT编译器与Interpreter解释器共存,当字节码只需要编译一次时都会使用Interpreter解释器来执行,因为它的速度比JIT快,而当一段字节码会被反复编译时,即过热,这时会使用JIT编译器编译,它有一个内部储存空间,相当于将编译后的机器码储存,而不用再次编译,这样会效率更高。
即编译提升效率,解释节约空间
2019.9.24补充
类加载器分为三部分:
- BootStrap 根类加载器
- 加载JVM依赖的相关jar资源
- rt.jar
- dt.jar
- tools.jar
- 加载JVM依赖的相关jar资源
- 扩展加载器ExtCalssLoader
- 加载环境相关jar资源
- 应用加载器AppClassLoader
- 加载的是开发的代码
- 根据应用加载器可以自定义类加载器
- 双亲委托机制:
1-类加载器收到类加载的请求,会先在加载器中使用findLoadedClass(name)方法,如果结果为Null,进行第二步;
2-把这个请求委托给父加载器去完成,,如果返回值依旧为null,一直向上委托,直到启动类加载器;
3-启动器加载器检查能不能加载(使用findClass()方法),能就加载(结束);否则,抛出异常,通知子加载器进行加载。
4-重复步骤三;
注意:每一个加载器都有一个父类加载器,但父类加载器不是这个加载器的父类,这是两个不同的概念需要区分,此处的父指的是层级关系而不是继承关系
这个双亲委托机制的作用在于,保护系统级别的类不被篡改,因为如果篡改了,将会在bootstrap loader中加载,而不会运行