JVM --- 笔记

虚拟机

java8API地址https://docs.oracle.com/javase/8/docs/api/

jvm8 地址https://docs.oracle.com/javase/specs/jvms/se8/html/

JVM --- 笔记

一、类加载子系统

JVM --- 笔记

(一)类的加载过程

1.加载阶段(将类以二进制流形式加载到JVM方法区中生成Class对象。)

(1)通过一个类的全限定名获取定义此类的二进制字节流。

(2)将字节流所代表的静态存储结构转为方法区的运行时数据结构。

(3)在内存中生成代表此类的java.lang.Class对象,作为方法区中这个类的访问入口。

2.链接阶段

(1)验证(Verify)

**确保字节流文件信息符合虚拟机规范,**保证类加载准确性,有格式、元数据、字节码验证等。

(2) 准备(Prepare)

为类变量分配内存,初始化零值。(Static修饰的变量)

这里不包含final修饰的static,因为final修饰的会在编译时就分配了。准备阶段显示初始化。

类变量分配在方法区,实例变量随对象一起分配在堆内存。这里不会为实例变量分配初始化。

(3)解析(Resolve)

将常量池中的符号引用转为直接引用。

3. 初始化

执行类构造器方法()的过程。此方法不需要定义,时虚拟机视角下的。此时会给类变量显示赋值。

一个类只能被加载一次。会被同步加锁。

(二)类加载器的分类

JVM --- 笔记

JVM --- 笔记

1.虚拟机自带的加载器

JVM --- 笔记

启动类加载器 (Bootstrap Class Loader)
  • 该类由c/c++实现。嵌套在jvm中。
  • 用来加载java的核心类库,用于提供JVM自身需要的类。
  • 并不继承java.lang.ClassLoader,没有父加载器。
  • 只加载java、javax、sun等开头的类(核心类库)
应用程序类加载器(System Class Loader)
  • java语言编写,由sun.misc.Launcher$AppClassLoader实现。

JVM --- 笔记

扩展类加载器(Extension Class Loader)
  • java语言编写。
用户自定义类加载器

什么情况下使用

  • 隔离加载类 不同框架整合在一起,中间件等,会存在类的冲突,使用该方式隔离框架之间、中间件之间隔离
  • 防止源码泄露。

(三) 类的双亲委派机制

JVM --- 笔记

1. 工作原理

类加载器收到类加载请求,首先向上找其父类,直到找到引导类,看起是否可以加载,不能则从引导类往下的子类进行尝试。

这样做的目的是类的加载首先去java核心类库中找是否有,核心类库的优先级最高,依次往下。

2. 优势

  • 避免类的重复加载。
  • 保护程序安全性,防止核心API被篡改。
    • eg:自定义的java.lang.String 是不会被加载的。
    • eg:自定义的java.lang.Maotao 加载会报错。自己定义和核心类库的包名一致,为了保护引导类加载器,会抛出安全异常。

3. 沙箱安全机制

保证核心API源代码的保护,引导类加载器只加载核心API,不加载自定义的与核心API同名或同包名的API。

(四)其他

jvm中比较两个calss是否为同一类,存在两个必要条件:

  • 类的完整类名必须一致,包括包名。
  • 类的类加载器必须一致。

二、 运行时数据区

JVM --- 笔记

灰色的PC程序计数器、本地方法栈、虚拟机栈是属于线程私有的。

红色的方法区和堆是属于进程的,同一个进程内的线程共享该内存。

线程

线程是一个程序里的运行单元。JVM允许一个应用有多个线程并行执行。

在Hotspot中,java线程与操作系统的本地线程是有直接映射关系。一一对应。

(一)PC程序寄存器

作用: 用来存储指向下一条指令的地址。行号的表示。

生命周期 : 线程私有,生命周期与线程一致。

执行:任何时间,一个线程只执行一个方法,程序计数器会保存当前正在执行方法的JVM指令地址。若执行本地方法则为空。

无OutMemoryError情况:Java虚拟机规范中唯一一个不会内存溢出的内存。