1 入门部分
1.1 为什么要学习JVM?
第一:为了面试(企业招聘战略在升级,业务和技术问得越来越深)
第二:为了更好的理解Java。
第三:为了更好的解决线上问题。
1)实现线上软件升级。(热替换-在线升级)
2)更好防止内存泄漏,提高内存的有效使用率。
3)更好提高系统的吞吐量。(GC时可能会暂停系统)
1.2 你了解哪些JVM产品?
Oracle公司的HotSpot。
IBM公司的J9。
阿里公司的TaobaoVM。
......
1.3 JVM的构成有哪几部分?
第一:类加载子系统(负责将类读到内存,效验类的合法性,对类进行初始化)
第二:运行时数据区(负责存储类信息,对象信息,执行逻辑)
第三:执行引擎(负责从指定地址对应的内存中读数据然后解释执行以及GC操作)
第四:本地库接口(负责实现Java语言与其他编程语言之间的协同)
2 类加载部分
2.1 你知道哪些类加载器?
1)BootSrtapClassLoader (根类加载器,使用C编写,负责加载基础类库中的类,例如Object)
2)ExtClassLoader (扩展类加载,负责加载JDK自带的扩展类,例如javax.xxx包中的类)
3)AppClassLoader (应用类加载器,负责加载我们自己写的类)
4)自定义ClassLoader(当系统提供的默认类加载器不满足我们需求时,可以自己创建)
2.2 为什么需要多个类加载器?
每个类加载器都有自己的加载职责,负责从不同位置加载我们所需要的类,同时可以基于需求进行懒加载(按需加载),例如:
1)加载基础类库(核心类库)
2)扩展类库
3)三方类(MyBatis、Spring...)
4)自己的类
2.3 什么是双亲委派类加载模型?
所谓双亲委派模型可以简单理解为向上询问、向下委派。当我们的类在被加载时,首先会询问类加载器对象的parent对象(两者之间不是继承关系),是否已经加载过此类,假如当前parent没有加载过此类,则会继续向上询问它的parent,依次递归。如果当前父加载器可以完成类加载则直接加载,假如不可以则委托给下一层类加载器去加载(可以理解为逐层分配任务)
2.4 双亲委派方式加载类有什么优势、劣势?
通过双亲委派类加载机制,保证同一个类只能被加载一次,同时也是对类资源的一种保护。例如我们自己也写了一个java.lang.Object类,为了保证Java官方的java.lang.Object类加载后不再加载我们的Object就可以使用双亲委派机制。但是这里也有要给缺陷,例如我们同一个JVM下有多个项目,但是不同项目中有包名类名都相同的类(类中的内容是不同的),此时只能有一个项目中的类会被加载,其他项目则无法加载。还有这种双亲委派模型可能会因为向上询问和向下委托,多少会影响一些性能。
2.5 描述一下类加载时候的基本步骤是怎样的?
第一:查找类(例如通过指定路径+类全名找到指定类)
第二:读取类(通过字节输入流读取类到内存,并将类信息存储到字节数组)
第三:对字节数组中的信息流进行效验分析以及初始化并将其结构内容存储到方法区。
第四:创建字节码对象(java.lang.Class),基于此对象封装信息的引用,基于这些引用获取方法区类信息。
2.6 什么情况下会触发类的加载?
我们可以将类的加载分为显式加载和隐式加载,显式加载是通过类加载器的loadClass方法或Class类的forName方法直接对类进行加载。隐式加载一般指构建对象、访问类中属性或方法时触发的类加载。
2.7 类加载时静态代码块一定会执行吗?
不一定,静态代码块是否会执行,取决于类加载时,是否会执行类初始化。
2.8 如果理解类的主动加载和被动加载?
主动加载:访问本类成员或方法时触发的加载。
被动加载:访问本类(当前类)对应的父类属性时,本类(当前类)属于被动加载。被动加载不会触发当前类的初始化。
2.9 为什么要自己定义类加载器,如果定义?
当系统提供的类加载器不能完全满足我们需求时,我们可以考虑自定义类加载器,例如:
1