初识jvm
jvm是什么?
jvm(java虚拟机),主要是解释和运行java字节码文件。
jvm的功能
- 解释和运行:将字节码指令解释成机器码供计算机执行。
- 即时编译:提前编译热点代码提高代码执行效率,使得java程序的性能可以接近c,c++程序。
- 内存管理:jvm可以在java程序运行过程中自动进行内存分配和垃圾回收。
jvm的组成
类加载器
字节码文件的组成
- 基本信息
对于以上基本信息中的版本号,jdk的版本号=主版本号-44
- 字段
3. 方法
4. 属性
5. 常量池
如何查看字节码文件
- 使用javap -v
- jclasslib
- arths
类的生命周期
- 加载:字节码文件的加载可以是本地,网络或动态生生成,将加载后的字节码信息保存在方法区中,生成一个InstanceKlass对象,保存类的所有信息,同时会在堆中生成类似的一个对象
- 链接
1.验证:是否符合jvm规范 2.准备:给静态变量赋值
3.解析:将符号引用转为直接引用
- 初始化
- 使用
- 卸载
示例代码:
public class Test {
public static void main(String[] args) {
System.out.println("A");
new Test();
new Test();
}
//每次创建对象时执行
public Test(){
System.out.println("B");
}
//实例代码块,每次创建对象时执行
{
System.out.println("C");
}
//类加载时执行
static {
System.out.println("D");
}
}
结果:DACBCB
public class Test {
public static void main(String[] args) {
new Child(); //如果去掉这行,只访问父类的静态变量不会导致子类初始化,因此结果为1
System.out.println(Child.a);
}
}
class Child extends Par1 {
static {
a=2;
}
}
class Par1{
public static int a=0;
static {
a=1;
}
}
//执行顺序,(1)new Child()首先父类加载并初始化,a=0,a=1;(2)子类加载a=2并初始化,(3)结果:2
类加载器的分类
启动类加载器
默认加载jre/lib下的类。通过将类放到jre/lib目录下或者使用(-Xbootclasspath/a:jar包目录/jar包名)可以让启动类来加载目标类。
扩展类加载器
默认加载jre/lib/ext下的类。同样可以通过将类放到/jre/lib/ext目录下或者使用(-Djava.ext.dirs=jar包目录)进行扩展。
应用程序类加载器
默认加载classpath下的类。
对于扩展类加载器和应用程序类加载器位于sun.misc.Launcher中,是一个静态内部类。继承自URLClassLoader。具备通过目录或者指定jar包将字节码文件加载到内存中。
自定义类加载器
打破双亲委派机制的方法
自定义类加载器重写loadClass方法
例如tomact通过自定义类加载器实现应用隔离,不同的应用之间使用不同的类加载器去加载应用类,对于系统类,不同的容器内的系统类是同一个,并不会被重复加载。
使用线程上下文类加载器
SPI机制示例:
public interface DriverManager {
String getDataBaseUrl();
String getConnection();
String getDriverClassName();
void closeConnection();
}
public class MysqlDriverManager implements DriverManager{
@Override
public String getDataBaseUrl() {
System.out.println("MysqlDriverManager getDataBaseUrl");
return "jdbc:mysql://localhost:3306/test";
}
@Override
public String getConnection() {
System.out.println("MysqlDriverManager getConnection");
return "com.mysql.jdbc.Driver";
}
@Override
public String getDriverClassName() {
System.out.println("MysqlDriverManager getDriverClassName");
return "com.mysql.cj.jdbc.Driver";
}
@Override
public void closeConnection() {
System.out.println("Connection closed");
}
}
public class PostgreSqlDriver implements DriverManager{
@Override
public String getDataBaseUrl() {
System.out.println("PostgreSqlDriver getDataBaseUrl");
return "jdbc:postgresql://localhost:5432/test";
}
@Override
public String getConnection() {
System.out.println("PostgreSqlDriver getConnection");
return "org.postgresql.Driver";
}
@Override
public String getDriverClassName() {
System.out.println("PostgreSqlDriver getDriverClassName");
return "org.postgresql.Driver";
}
@Override
public void closeConnection() {
System.out.println("Connection closed");
}
}
//这里就会将在META-INF/com.guolihong.javaLearn.spi.DriverManager 中配置的实现加载。
public class Test {
public static void main(String[] args) {
ServiceLoader<DriverManager> load = ServiceLoader.load(DriverManager.class);
load.forEach(driverManager -> {
System.out.println("------------------");
System.out.println(driverManager.getConnection());
System.out.println(driverManager.getDriverClassName());
System.out.println(driverManager.getDataBaseUrl());
driverManager.closeConnection();
});
}
}
在META-INF/com.guolihong.javaLearn.spi.DriverManager
com.guolihong.javaLearn.spi.MysqlDriverManager
com.guolihong.javaLearn.spi.PostgreSqlDriver