直接硬背八股实在太痛苦了,系统刷一遍吧....
一张图开始
JVM功能
1解释和运行:对字节码文件中的指令,实时的解释成机器码,让计算机执行
2.内存管理:自动为对象、方法等分配内存,自动的垃圾回收机制,回收不再使用的对象
3.即时编译(JIT):对热点代码进行优化,提升执行效率
实时解释虚拟机指令,不做任何优化性能不如C/C++
常见的JVM
JVM的组成
类加载器、运行时数据区,执行引擎、本地接口见下图
字节码文件(核心:字节码指令)
应用场景
如:int i=0;i=i++;最终i的值是多少(这个我知道是0),java反射如何实现,版本冲突和系统升级等
查看字节码文件:jclasslib工具
组成(五个部分):
1.基础信息:魔数、字节码文件对应的Java版本号,访问标识(public final 等等),父类和接口
2.常量池:保存了字符串常量、类或接口名、字段名主要在字节码指令中使用
3.字段:当前类或接口声明的字段信息
4.方法:当前类或接口声明的方法信息字节码指令
5.属性:类的属性,比如源码的文件名内部类的列表等
魔数
其实通过文件扩展名是无法确定文件类型,随意修改扩展名也不会影响文件的内容,软件实际上是使用文件的头几个字节去校验文件的类型(涨知识),将文件头称为魔数。
主副版本号
主版本号用来表示大版本号(主版本号-44),副版本号是当主版本号相同时作为区分不同版本的标识,一般关注主版本号就够了。版本号可以判断当前字节码的版本运行的JDK是否兼容(一般是本地JDK版本低于要求的版本,向上兼容不太现实。可以升级JDK版本(这可太麻烦了),或者更换依赖(其实一般只能这样))。上图
常量池
避免相同的内容重复定义,节省空间。比如字符串常量池(我现在就知道这一个)
常量池中的数据都有其编号,通过编号可以快速找到对应的指令(这令我想起了hashmap),这个过程称之为符号引用。
方法
存放字节码指令的核心位置,下图中,操作数栈是临时存放数据的地方,局部变量表是存放方法中局部变量的位置。(有点晦涩稍微)
iconst、istore、iload的作用下图很清晰
i=i++过程,iinc指定位置的值进行增加。++i的话就是把iinc 1 by 1放在load之前,结果就不一样了
答案模板:答案是0,我通过分析字节码指令发现,i++ 先把0取出来放入临时的操作数栈中,
接下来对i进行加1,i变成了1,最后再将之前保存的临时值0放入i,最后i就变成了0。
小例题,分析字节码看这三个指令性能的高低(字节码行数越少,一般性能越高)
int i=0,j=0,k=0;
i++;
j=j+1;
k+=1;
结论是j=j+1性能最低,另外两个都是1条指令,不过其实经过JIT编译之后差异很小,那可能还是看个人习惯了,算法题后遗症,我一般用i++(gpt推荐我用+=)
0 iconst_0
1 istore_1
2 iconst_0
3 istore_2
4 iconst_0
5 istore_3
6 iinc 1 by 1//i++的
9 iload_2
10 iconst_1
11 iadd
12 istore_2
13 iinc 3 by 1//k+=1的
2024.04.23.00:25过于困倦,明天再肝了只能