找到.java文件
词法分析器
tokens流
语法分析器
语义分析器
字节码生成器
转成.class文件
根据全限定路径名寻找class文件,转换成二进制流。 通过ClassLoder.load(String name)(类装载器,name:全限定路径名) 不同路径下的类,设置不同路径的类装载器。
$JAVA_HOME
中的 jar/lib/rt.jar
里所有的class或 Xbootclassoath
选项指定的jar包 $JAVA_HOME
中 jar/lib/*.jar
或 -Djava.ext.dirs
指定目录下的 jar
包 Djava.class.path
所指定目录下的类和 jar
包 java.lang.ClassLoader
的子类自定义加载class,属于应用程序根据自身需要自定义的 ClassLoader
,如 Tomcat
、 JBoss
都会根据j2ee规范自行实现 ClassLoader
需要把类文件 静态存储结构 里面对应的内容存储到JVM里面 (方法区的运行时数据结构)
代码里一段方法不宜过长(阿里规范中提到一段方法不应超过80行)。方法存到JVM里的栈帧。内容一旦超过一定行数或者过长时,JVM就会从编译性改变为解释性,从而导致性能下降。
验证
保证被加载的正确性。验证class文件中的 cafe babe 。注:class文件中,已 cafe babe 为开头的是java文件。
准备
为类的静态变量分配内存。如: private static int a = 3;//为a分配内存,并且将a初始化默认值,默认值:a=0
解析
符号引用:就是class文件中的内容,符合JVM规范的内容,JVM认识的语言。
直接引用:在Java进程中能够代表真实含义的。JVM更底层,计算机能够认识的语言,并且操作的。比方说为某个静态变量分配了真实的内存。
对类的静态变量,进行正真的初始化。就是将上一步中的准备过程中的 private static int a = 3;//为a分配内存,并且将a初始化默认值,默认值:a=0
。将3正真的赋值 a = 3。
程序最小单位是进程(数据不安全进程内的数据会被该进程内所有的线程共享),进程包含多个线程。
线程是进程最小的执行单位。
栈:只要符合栈结构,都遵循先进后出的原则
在Java方法中如何去调用C语言的方法,通过 动态链接 去调用完成。
栈帧(Java虚拟机栈、本地方法栈)Frame:代表是方法的执行。一个栈帧被创建就表示一个方法被执行,方法压栈先进后出。
//伪代码1 a(){ b(); } b(){ c(); } c(){ } //先进行压栈 //先往Java虚拟机中压栈存入a(),之后是b(),在之后是c()。 //之后是出栈 //在c()方法执行完之后先出,b()执行完再出,最后是a()执行完再出。 //先进后出的概念。 //伪代码2 a(){ a(); } //如果递归一直调用自己,超出栈的长度或深度,就会报StackOverflowError(栈溢出)。同理如果一个方法内部的调用链非常长或深的话也一样会报StackOverflowError(栈溢出)。
操作数栈:栈结构,用来描述运算过程当中数据暂时的存储位置
//伪代码.java文件 public static int calc(int op1,int op2){ op1 = 3; int result = op1 + op2; return result; } //.java文件的.class文件翻译的JVM字节码。 public static int calc(int op1,int op2); Code: 0:iconst_3 // 将3放到操作数栈中 //局部变量下标:如果是类级别方法【static修饰的方法】下标是从0开始;如果是实例方法下标从1开始,0标识的是这个实例,保留给当前对象的引用this。 1:istore_0 //将操作数占中的3赋值给局部变量表中的局部变量 2:iload_0 //将局部变量0值放到操作数栈中 3:iload_1 // 4:iadd 5:istore_2 6:iload_2 7:ireturn
Class Pointer:指向对象对应的类元数据的内存地址 64位系统:8字节 Length数组对象特有:数组长度 4字节
包含了对象的所有成员变量,大小由各个变量类型决定
short和char:2字节 int和float:4字节 long和double:8字节 reference:8字节(64位系统)
为了保证对象的大小为8字节的整数倍,会进行填充字节
赵小胖个人博客