阿华代码,不是逆风,就是我疯
你们的点赞收藏是我前进最大的动力!!
希望本文内容能够帮助到你!!
目录
[三:JVM的类加载机制(重点 )](#三:JVM的类加载机制(重点 ))
一:JVM引入
IDEA运行代码离不开三个东西
①JVM------Java虚拟机
②JRE------Java运行时环境
③JDK------Java开发工具包
③包含②,②包含①
1:编程语言
在计算机导论中,我们把编程语言可以分为:编译型语言和解释型语言(虽然现在不适用了)
**编译型语言:**将像JAVA或者C++这样的高级语言,转化为二进制的机器指令,最后由CPU进行执行
**解释型语言:**边转化二进制机器指令,CPU边执行
2:JAVA运行机制
Java属于"半编译,边解释",目的是为了**跨平台。**我们知道不同的cpu,上面支持的指令格式并不一样。JAVA想要达到编译一遍,就能在多种CPU上执行。这里的过程简述如下
①通过javac把.java文件转化为.class文件
(.class文件就是字节码文件,包含的就是java字节码,可以理解成java自己搞的一套"CPU指令")
②这个.class文件在某个具体的操纵系统上执行,此时JVM就会把.class文件转化为当前cpu能识别的机器指令。
(JVM相当于翻译官)
总结:我们编写和发布一个Java程序,只需发布一个.class文件就可以了,剩下的交给JVM(爹~!)
二:JVM中内存区域划分
JVM本身就是一个进程,在运行过程中就会向操作系统这里申请一些资源(内存),比如在Java中定义变量,就是jvm去申请内存空间
1:堆
代码中new出来的对象 就是在堆里面;对象中持有的非静态成员变量也就是在堆里
2:栈
包含了方法的调用关系和局部变量
(1)本地方法栈
本地也就是jvm内部 ,通过c++写的代码中的一些调和关系和局部变量(关注较少)
(2)虚拟机栈
记录Java代码中(IDEA中)的调用关系和局部变量(一般说栈默认指虚拟机栈)
注:这里说的栈,和数据结构中的栈不是一回事
3:程序计数器
这个区域空间比较小,用来存储下一条要执行的java指令地址
4:元数据区
java1.8以前也叫"方法区"。我们写的代码,由javac转化为字节码,再由jvm把字节码加载到内存中放到元数据区(方法区)中,程序就按照元数据中记录的字节码依次执行
"元数据" (meta data)计算机术语,指的是一些辅助性性质的,描述性质的属性
例如:类的信息,方法的信息,一个程序有哪些类,类里有哪些方法,方法中包含哪些指令
例如:文件大小、位置、拥有者、修改时间、
三:JVM的类加载机制(重点 )
1:类加载
指java进程运行时,把.class文件从硬盘读取到内存,并进行校验解析的过程
2:类加载过程
Java官方文档中有详细说明Java SE Specifications
(1)加载
找到硬盘上的.class文件,打开文件,读取文件内容(二进制数据)
(2)验证
确保读取到的数据内容是合法的.class文件(字节码文件)
①类型
c++中没有规定类型有多长,而是规定这个类型不能短于多长,所以程序员用typedef自己定义出一些类型,u4,u2就是在描述这个类型的长度
②magic
majic也叫做magic number 魔幻数字,广泛应用于二进制文件格式中,用来标识当前二进制文件的格式是哪种类型
③JVM内部的版本,高版本的JVM可以运行低版本的.class文件,反之不一定可以
④常量池
⑤针对类的修饰限定符只有public和default两种
⑥当前类的其它信息和父类息
⑦每一个元素就是一个field_info,描述每一个成员,属性的相关信息(属性的名字、类型,访问权限,)
⑧方法信息
⑨注解
(3)准备
给类对象申请内存空间,此时申请到的内存空间,里面的默认值都是0
(4)解析
针对字符串常量进行处理------JVM将常量池中的符号引用替换为直接引用的过程,也就是初始化常量的过程
等.class文件被JVM加载到内存当中后,此时"hello"就有真实的地址了
(5)初始化
针对对象完成后续的初始化
3:双亲委派模型
双亲委派模型是处于加载环节中的,它描述的是如何查找.class文件
彩蛋:起"双亲"为名字,纯是为了好听,其实单亲更符合实际
(1)类加载器
在JVM中有一个专们进行类加载的模块------"类加载器"(ClassLoader)
默认的类加载器有三个:
①BootstrapClassLoader------负责查找标准库的目录
注:Java语法规范中描述了标准库中应该有哪些功能,像我们熟知的java.lang,java.util等就是标准库中的核心组件
②ExtensionClassLoader------负责查找扩展库的目录
注:实现JVM的厂商/组织,会在标准库的基础上在扩展实现一些功能,这些功能就放在扩展库里
③ApplicationClassLoader------负责查找当前项目的代码目录和第三方库目录
注:上述三个类加载器,存在像二叉树里那种"父子关系",有一个指针引用指向自己的"父亲"类加载器
(2)模型工作过程
①将ApplicationClassLoader作为入口进入,ApplicationClassLoader不会选择立刻在自己的目录开始搜寻,而是把任务交给自己的parent
②ExtensionClassLoader收到任务后,不会立刻搜索自己的目录,而是传给parent
③BootstrapClassLoader同样把任务甩给parent,但是发现parent是null,没有"父亲"
④所以只能自己搜寻了------尝试在标准库中搜寻符合要求的.class文件。如果找到了,就步入下一个验证环节;如果没找到就把任务返还孩子
⑤ExtensionClassLoader收到搜寻任务后同样再扩展目录中开始搜寻,如果找到了,就步入下一个验证环节;如果没找到就把任务返还孩子
⑥ApplicationClassLoader收到任务在当前项目代码目录和第三方库目录中找,如果找到了,就步入下一个验证环节;如果没找到就表示类加载失败抛出"ClassNotFoundException"异常
注:上述的规则,是JVM自带的类加载器默认遵循的规则。我们也可以自己写一个类加载器,打破上述规则(铁批表示规则就是用来打破的~~~)