JVM问题

一、JDK中包含了哪些内容?

①.JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE,就不用单独安装JRE了。其中的开发工具:编译工具(javac.exe)打包工具(jar.exe)等。

②.JRE(Java Runtime Environment Java运行环境):包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。

二、三大商业虚拟机

①.sun公司的HotSpot VM(后来被Oracle收购)

②.BEA JRocket VM(后来被Oracle收购),JRocket虚拟机中没有解释器,全部代码都靠即时编译器编译后执行。

③.IBM J9

三、对JVM整体的理解

①.类加载子系统

②.运行时数据区【核心关注:栈,堆,方法区】

③.执行引擎(解释器和JIT编译器共存)

在这里插入图片描述

四、简述Java类加载机制(Java类加载过程)

PS:加载机制是指类的加载,链接,初始化的过程。

在这里插入图片描述

五、什么是类的加载、链接、初始化

①.加载:将字节码文件中的.class文件,通过类加载器,加载进运行时数据区的方法去内,并创建一个大的Class对象

②.链接:(验证、准备、解析)

1.验证(比如说验证字节码文件开头是CAFFBABA,版本号等)

2.准备(为类变量赋予默认的初始化值,使用static+final修饰,且显示赋值不涉及到方法或者构造器调用的基本数据类型或者String类型的赋值都在准备阶段)

3.解析:将类中的字符引用变成直接引用(符号引号的字节码文件的常量池中)

③.初始化:为类变量赋予正确的初始化值,执行Clinit方法(静态代码块使用static修饰的变量)

PS:一个类中声明类变量,但是没有明确使用类变量的初始化语句以及静态代码块来执行初始化操作时

六、类的主动使用和被动使用

①.当创建一个类的实例时,比如使用new关键字,或者通过反射、克隆、反序列化

②.访问某个类或接口的静态变量,或者对该静态变量赋值

③.调用类的静态方法

④.反射(比如:Class.forName("com.xiaozhi.Test"))

⑤.初始化一个子类(当初始化子类时,如果发现其父类还没有进行过初始化,则需要先出发其父类初始化)

⑥.当虚拟机启动时,用户需要指定一个执行的主类(包含main()方法的那个类),虚拟机会先初始化这个类

⑦.JDK7开始提供的动态语言支持(涉及解析REF_getStatic、REF_putStatic、REF_invokeStatic方法句柄对应的类)

PS:除了主动使用其余都是被动使用

七、.forName("Java.lang.String")和loadClass("Java.lang.String")有什么区别

①.forName()会导致类的主动加载,而getClassLoader()不会导致类的主动加载,Class.forName()是一个静态方法,最常用的是Class.forName(String className);根据传入的类的全限定名返回一个Class对象。该方法在将Class文件加载到内存的同时,会执行类的初始化。

②.ClassLoader.loadClass():这是一个实例方法,需要一个ClassLoader对象来调用该方法。该方法将Class文件加载到内存时,并不会执行类的初始化,直到这个类第一次使用时才进行初始化。(该方法因为需要得到一个Class Loader对象,所以根据需要指定使用哪个类加载器)

八、 判定一个常量是否“废弃”还是相对简单,而要判定一个类型是否属于“不再被使用的类”的条件就比较苛刻了。需要同时满足下面三个条件

①.该类所有的实例都已经被回收。也就是Java堆中不存在该类及其任何派生子类的实例。

②.加载该类的类加载器已经贝回收。这个条件除非是精心设计的可替换类加载器的场景。如JSP重加载等,否则通常时很难达成的。

③.该类对应的Java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

九、说说类的加载器分类?

①.JVM支持两种类型的类加载器,分别为引导类加载器(Bootstrap ClassLoader)和自定义类的加载器(User-Defined ClassLoader)

②.从概念上讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范并没有这么定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为类加载器

在这里插入图片描述

十、说说你对引导类加载器、扩展类加载器和应用程序加载器的理解

①.引导类加载器

1.这个类加载使用C/C++语言实现的,嵌套在JVM内部

2.它用来加载Java核心类库(JAVA_Home/jre/lib/rt.jar、resource.jar或sum.boot.class.path路径下的内容),用于提供JVM自身需要的类(String类就是使用这个类加载器)

3.由于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类

4.不继承自java.lang.ClassLoader,没有父类加载器

②.扩展类加载器 Extension

1.Java语言编写,由sum.music.Launcher$ExtClassLoader实现

2.派生于ClassLoader类,父类加载器为启动类加载器

3.从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载

③.系统类加载器 Application

1.Java语言编写,由sum.music.Launcher$AppClassLoader实现

2.派生于ClassLoader类,父类加载器为扩展类加载器

3.它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库

4.调用System.getSystemClassLoader()|Thread.currentThread().getContextClassLoader()获取到的是系统类加载器

十一.谈谈你对双亲委派机制的理解

①.如果一个类加载收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类加载器去执行

②如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器

③如果父类的加载器可以完成类的加载任务,就成功返回,倘若父类加载器无法完成此项加载任务,子加载器才会尝试自己去加载,这就是双亲委派机制

十二.双亲委派机制的优势

①.避免类的重复加载,确保一个类的全局唯一性(当父ClassLoader已经加载了该类的时候,就没有必要子ClassLoader再加载一次)比如:我们如果十引导类加载器加载了,就没必要再一次使用扩展类加载器进行加载

②.保护程序安全,防止核心API被随意篡改

在这里插入图片描述

十三.双亲委托模式的弊端

检查类是否加载的委托过程是单项的,这个方式虽然从结构上说比较清晰,使各个ClassLoader的职责非常明确,但是同时会带来一个问题,即顶层的ClassLoader无法访问到底层的ClassLoader所加载的类

十四.双亲委派机制可以打破吗?为什么

①.双亲委派模型的第一次“被破坏”其实发生在双亲委派模型出现之前——即JDK 1.2面世以前的“远古时代”

②.第二次破坏双亲委派机制:线程上下文类加载器(ClassLoader.getSystemClassLoader())

③.双亲委派模型的第三次“被破坏”是用于用户堆程序动态性的追求所导致的。如:代码热替换(Hot Swap)、模块热部署(Hot Deployment)

十五.沙箱安全机制谈谈你的认识

自定义String类,但是在加载String类的时候会使用引导类加载器进行加载,而引导类加载器在加载过程中会先加载jdk自带的文件(rt.jar包中的java/lang/String.class),报错信息说没有main方法就是因为加载的是rt.jar包中的String类。这样可以保证对java核心源代码的保护,这就是沙箱安全机制在一定程度上可以保护程序安全,保护原生的JDK代码

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐