JVM笔记

JVM

1.JVM的体系结构

2.类加载器

类加载机制:Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。

类型的加载、链接和初始化过程都是在程序运行期间完成的

注意:加载、验证、准备、初始化、卸载着五个阶段的顺序是确定的,解析不一定。

被动引用:

  • 通过子类引用父类的静态字段,不会导致子类初始化

  • 通过数组定义来引用类,不会触发此类的初始化

  • 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化

类加载过程:加载、验证、准备、解析、初始化

加载:

  • 通过一个类的全限定类名来获取定义此类的二进制字节流

  • 将这个字节里所代表的静态存储结构转化为方法区的运行时数据结构

  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这类的是各种数据的访问入口

验证:Java虚拟机如何不检查输入的字节流,很可能因为载入了有错误或者有恶意企图的字节码流为导致整个系统受攻击甚至崩溃。

  • 文件格式验证:是否符合Class文件格式的规范

  • 元数据验证:对字节码描述的信息进行语义分析

  • 字节码验证:通过数据流分析和控制流分析,确定程序语义是合法的、符合逻辑的

  • 符号引用验证:确保解析行为正常执行,发生在虚拟机将符合引用转化为直接引用的时候

准备:正式为类中定义的变量(静态变量)分配内存并设置类变量初始值的阶段

解析:Java虚拟机将常量池内的符号引用替换为直接引用的过程

  • 类或接口的解析

  • 字段解析

  • 方法解析

  • 接口方法解析

初始化:Java虚拟机开始真正执行类中编写的Java程序代码,将主导权移交给应用程序

初始化阶段就是执行类构造器<clinit>()方法的过程

3.双亲委派机制

类加载器:”通过一个类的全限定类名来获取定义此类的二进制字节流“这个动作放到Java虚拟机外部去实现,以便让应用程序自己去决定如何去获取所需的类

Java虚拟机角度:

两种不同的类加载器:

  • 启动类加载器(Bootstrap ClassLoader) C++实现,虚拟机自身的一部分

  • 其它所有的类加载器,Java语言实现,独立存在于Java虚拟机外部,全都继承自抽象类java.lang.ClassLoader

Java开发人员角度:

  • 启动类加载器(Bootstrap ClassLoader)

  • 扩展类加载器(Extension Class Loader)

  • 应用程序类加载器(Application Class Loader) getSystemClassLoader()的返回值 因此也被称为系统类加载器,也是程序默认的类加载器

双亲委派模型工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。

4.Java内存模型(JMM)

定义程序中各种变量(实例字段,静态字段和构成数组对象的元素)的访问规则

JMM的8种原子操作:

  • lock(锁定):作用于主内存的变量,它把一个变量标记为一条线程独占状态;

  • unlock(解锁):作用于主内存的变量,它将一个处于锁定状态的变量释放出来,释放后的变量才能够被其他线程锁定;

  • read(读取):作用于主内存的变量,它把变量值从主内存传送到线程的工作内存中,以便随后的load动作使用;

  • load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存中的变量副本中;

  • use(使用):作用于工作内存的变量,它把工作内存中的一个变量的值传递给执行引擎,每当虚拟机遇到一个需要给变量赋值的字节码指令时,将会执行这个动作;

  • assign(赋值):作用于工作内存的变量,它把从执行引擎获取的值赋值给工作内存中的变量,每当虚拟机遇到一个给变量赋值的指令时候,执行该操作;

  • store(存储):作用于工作内存的变量,它把工作内存中的一个变量的值传送给主内存中,以便随后的write操作使用;

  • write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。

执行上述8种基本操作时必须满足如下规则:

  • 不允许read和load、store和write操作之一单独出现(即不允许一个变量从主存读取了但是工作内存不接受,或者从工作内存发起回写了但是主内存不接受的情况),以上两个操作必须按顺序执行,但没有保证必须连续执行,也就是说,read与load之间、store与write之间是可插入其他指令的。

  • 不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。

  • 不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存。

  • 一个新的变量只能从主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话说就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。

  • 一个变量在同一个时刻只允许一条线程对其执行lock操作,但lock操作可以被同一个条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。

  • 如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。

  • 如果一个变量实现没有被lock操作锁定,则不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定的变量。

  • 对一个变量执行unlock操作之前,必须先把此变量同步回主内存(执行store和write操作)。

posted @ 2020-05-05 15:26  pengxiaowei  阅读(92)  评论(0)    收藏  举报