jvm面试常问(二)

1 什么是字节码,字节码的好处

java源代码 --> 编译器(javac命令) --> jvm可执行的java字节码--> jvm中的解释器 ---> 机器可执行的二进制机器码-->程序运行

好处: 运行在jvm中,可以跨平台, 由于是运行字节码,无需再次编译,比解释型语言效率高

 2 jvm调优

 3. 垃圾回收算法

3.1 标记清除算法 MarkSweep

把垃圾内存标记出来,然后再垃圾回收器再清除这些垃圾内存, 缺点: 会造成很多垃圾碎片

3.2 拷贝算法Copying

将内存分为两半, 每次只使用一半,垃圾回收时,将这一半中的存活对象拷贝到另一半,然后再清楚这一半,这样就解决了内存碎片问题,

缺点: 资源利用率少,一半空闲内存。如果存活对象过多,拷贝的次数就多,性能就低。

3.3 标记压缩算法 Mark

 把垃圾内存标记出来,并且把存活的对象往同一端移动,移动完所有存活对象后,就将剩余的一端清除掉

优点: 效率更高,没有内存碎片

 4 jvm内存模型

栈: 分为jvm栈和本地栈

堆: 分为新生代和老年代

新生代: 分为Eden区和2个survivor区

元数据区MetaSpace : 存放一些类和常量信息

 5 类加载机制

当一个类加载器收到了类加载的请求的时候,他不会直接去加载指定的类,而是把这个请求委托给自己的父加载器去加载。只有父加载器无法加载这个类的时候,才会由当前这个加载器来负责类的加载。

Java中提供如下四种类型的加载器,每一种加载器都有指定的加载对象,具体如下

Bootstrap ClassLoader(启动类加载器) :主要负责加载Java核心类库,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。

Extention ClassLoader(扩展类加载器):主要负责加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。

Application ClassLoader(应用程序类加载器) :主要负责加载当前应用的classpath下的所有类

User ClassLoader(用户自定义类加载器) : 用户自定义的类加载器,可加载指定路径的class文件

这四种类加载器存在如下关系,当进行类加载的时候,虽然用户自定义类不会由bootstrap classloader或是extension classloader加载(由类加载器的加载范围决定),但是代码实现还是会一直委托到bootstrap classloader, 上层无法加载,再由下层是否可以加载,如果都无法加载,就会触发findclass,抛出classNotFoundException.

双亲委派的优势:

避免重复加载 + 避免核心类篡改

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心JavaAPI发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

双亲委派的劣势:

不能向下逆向加载

在双亲委派模型中,子类加载器可以使用父类加载器已经加载的类,而父类加载器无法使用子类加载器已经加载的。这就导致了双亲委派模型并不能解决所有的类加载器问题。

双亲委派的破坏

第一次,历史原因,在jdk1.2开始引入双亲委派机制,那么在此之前如 jdk1.1的时候,存在的自定义的类加载器,它们就不符合双亲委派。而实际上,我们可以继承ClassLoader类,然后重写loadClass方法,也可以打破双亲委派。(打破双亲委派,不一定是坏事)

第二次,SPI机制引入了线程上下文特意打破双亲委派,后面撸源码会提到。

第三次,用户对程序动态性的追求导致的;即:代码热替换、模块热部署。

OSGi实现模块化热部署的关键则是它自定义的类加载器机制的实现。每一个程序模块(Bundle)都有一个自己的类加载器,当需要更换一个Bundle时,就把Bundle连同类加载器一起换掉以实现代码的热替换。在OSGi幻境下,类加载器不再是双亲委派模型中的树状结构,而是进一步发展为更加复杂的网状结构。

第四次,是JDK9,引入了模块化,当平台及应用程序类加载器收到类加载请求,在委派给父加载器加载前,要先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就要优先委派给负责哪个模块的加载器完成加载。

经过破坏后的双亲委派模型更加高效,减少了很多类加载器之间不必要的委派操作。

posted @ 2023-03-24 10:00  剑阁丶神灯  阅读(13)  评论(0编辑  收藏  举报