【笔记】JVM 找门必备【持续更新中】

目录

JVM是什么?

掌握JVM后,能做什么?

相关产品

JVM结构

ClassLoader System 类加载系统

Parents Delegation Model 双亲委派机制

类的加载方式

类的加载过程


JVM是什么?

JVM(Java Virtual Machine)是Java 虚拟机的简称,它是一个可以执行 JAVA 字节码的虚拟 计算机。

掌握JVM后,能做什么?

  • 防止内存泄漏(Memory Leak)
  • 科学使用垃圾回收器(GC)
  • 优化线程锁(Thread Lock)的使用
  • 提高系统性能,降低系统延迟(Delay)
  • 提高系统吞吐量

相关产品

  • TaoBaoJVM (国内阿里团队研发)
  • J9 (IBM团队 内网使用)
  • HotSpot (Sun公司研发)

JVM结构

JVM由四大部分组成

  • ClassLoader System 类加载系统: 负责加载类到运行内存中
  • Runtime Data Area 运行时数据区: 负责存储对象、数据和方法
  • Execution Engine 执行引擎:编译执行字节码文件,执行GC
  • Native Interface 本地接口: 运行别的编程语言 为Java 所用

ClassLoader System 类加载系统

类加载系统负责加载类,验证类,解析类,初始化类对象,并转换为字节码文件。

  • Bootstrap ClassLoader 基础类加载器,用C++编写,加载核心库,不能被Java调用,常见的String、Object基础类和包装类,由这个加载器完成,此外可加载这些包 JAVA_HOME/jre/lib/rt.jarresources.jarsun.boot.class.path
  • ExtClassLoader  扩展类加载器,负责加载JAVA_HOME\lib\ext目录中的,或通过java.ext.dirs系统变量指定路径中的类库
  • AppClassLoader 应用类加载器,常用,自己写的类、Spring、Mybatis 等
  • 自定义类加载器,应用于同包名类的加载,或者解析加密的class文件

Parents Delegation Model 双亲委派机制

双亲委派模型可以简单理解为向上询问、向下委托。

值得注意的是,图中的parent child关系并非继承关系

以加载User自定义类为例,类加载器从AppClassLoader开始向上询问,其parent是否加载User,若ExtClassloader未加载,则继续向上询问BootstrapClassLoader是否加载了User,当BootstrapClassLoader发现自己未加载,则从BootstrapClassLoader开始尝试是否能加载该类,若未能加载,进一步传递给ExtClassloader加载,若未能加载,最终传递给AppClassLoader加载。

优点:

  • 保证同一个包路径下的同一个包名类 有且仅会加载一次,保证了系统的健壮性(robustness)

缺点:

  • 运行效率降低。手写的类,往往是由AppClassloader加载,然而重新向上询问,向下委托,往往是多余的。
  • 若一定要加载同包名类,在双亲委派模型中,是不能被完成的,只有引入手写的自定义类加载器。

类的加载方式

  • 显式加载,直接调用类加载器,例如启动mysql的驱动:
Class.forname("com.mysql.cj.jdbc.Driver");
  • 隐式加载,通过new对象,或者调用静态方法时,加载类对象。

类的加载过程

 

加载阶段

 .class文件的路径 决定了类加载器的不同,再交由各自类加载器完成类的加载,文件通过IO流进入JVM中。

连接阶段

  1. 校验,校验类结构信息的合法性
  2. 准备,对类变量进行默认初始化,为类变量设置分配内存
  3. 解析,虚拟机将常量值中的符号引用替换为直接引用,简单的来说,如果对象A引用了对象B的一个方法b(),单单一句b()是不够的,虚拟机进一步帮助A类,找到B类中b()的实际位置。

初始化阶段

  • 主动使用
  • 被动使用,被动使用的类不会加载静态方法

准备代码: 

class A {
    static {
        System.out.println("A.static initializer");
    }

    public static void methodA() {
        System.out.println("A.methodA");
    }
}


class B extends A {
    static {
        System.out.println("B.static initializer");
    }

    public static void methodB() {
        System.out.println("B.methodB");
    }
}

执行:

A.methodA();

 可以得到:

A.static initializer
A.methodA

此时, A类为 主动加载,并且完成了A类的初始化

调整main函数中的代码:

//        A.methodA();
        B.methodA();

可以得到:

A.static initializer
A.methodA

此时,B类中的初始化并没有执行。这时 B类属于被动加载,完成初始化的A类属于主动加载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值