文章目录
说明:学习的时候看的是尚硅谷周阳老师的视频,我觉得很好,可以推荐大家看一下, b站视频链接,jvm的部分是p13~37部分,中间的p26好像出错了,大家看到这里可以去b站上找其他的视频。
JVM
1、JVM位置
JVM是运行在操作系统之上的,它与硬件没有直接的交互。
2、JVM体系结构概览
图中灰色区域是线程私有,占有的内存非常小,一般不存在垃圾回收GC。
图中亮色区域是线程共享,存在垃圾回收GC(GC方法区很少,一般都在堆)。
(1)类加载器ClassLoader(快递员)&执行引擎Execution Engine
负责加载class文件,class文件在文件开头有特定的文件标识,将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构并且ClassLoader只负责class文件的加载,至于它是否可以运行,由Execution Engine决定。
① 类加载器分类(考点)
- 虚拟机自带的加载器
- 启动类加载器(Bootstrap)C++写的
- 扩展类加载器(Extension)Java写的
- 应用程序类加载器(AppClassLoader)Java也叫系统类加载器System,加载当前应用的classpath的所有类
- 用户自定义加载器
Java.lang.ClassLoader的子类,用户可以定制类的加载方式。
② getParent()(考点)
public class test {
public static void main(String[] args) {
Object object = new Object();
System.out.println(object.getClass().getClassLoader());
//应该是Bootstrap启动类加载器,但是因为使用c++写的,所以打印结果为null
System.out.println(object.getClass().getClassLoader().getParent());//error,没有祖先了,null已经是祖先了
System.out.println(object.getClass().getClassLoader().getParent().getParent());//同上
test test = new test();
System.out.println(test.getClass().getClassLoader());
//打印结果:sun.misc.Launcher$AppClassLoader@18b4aac2
//jvm调用的入口程序:sun.misc.Launcher
System.out.println(test.getClass().getClassLoader().getParent());
//打印结果:sun.misc.Launcher$ExtClassLoader@61bbe9ba
System.out.println(test.getClass().getClassLoader().getParent().getParent());
//打印结果:null(即Bootstrap)
}
}
说明: 如果是java自带的类,那么是Bootstrap类加载器,如果是自己编写的,那么是AppClassLoader。
③ 双亲委派机制—保证沙箱安全
寻找一个类的过程:先去Bootstrap类找,找得到就用,找不到到Extension类找,再找不到到App类找,再找不到就报错。
package java.lang;
/**
* Created by luyangsiyi on 2020/1/31
*/
public class String {
/*
错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application
*/
public static void main(String[] args) {
System.out.println("java");
}
}
说明: 根据双亲委派机制,Bootstrap中存在java.lang.String这个类,就会直接去运行这个类,而不会运行自己写的,所以自带的类中没有main方法报错。
- 总结:
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。
采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样的一个Object对象(即使你重写一个java.lang.Object),沙箱安全机制。
加载后,执行引擎按照程序逻辑进行执行。
(2)本地方法栈/本地方法接口/本地方法库
① 多线程的例子
public class test {
public static void main(String[] args) {
Thread t1 = new Thread();
t1.start();
t1.start