【Java深入理解虚拟机】周志明 读书笔记

文章目录

  • 2. JVM内存管理
    • 2.2.Jvm 运行时内存区域2-18
      • 程序计数器
      • 虚拟机栈
      • Java堆
      • 运行时常量池
    • 2.3.虚拟机对象
      • 对象的创建
    • 3.2.对象存活判断方法
  • 7. 虚拟机类加载机制
    • 什么是虚拟机类加载机制?
    • 类的生命周期包括多少个阶段,分别是什么?
    • 类加载包括哪5个阶段?
    • 连接包括哪3个阶段?
    • 哪5个生命周期阶段的顺序是确定的?
    • 为什么解析阶段的顺序是不确定的?
    • 虚拟机规定了哪5种情况必须立即对类进行“初始化”?
    • 类加载中的加载完成哪些工作?
    • 类加载中的验证完成什么工作
    • 解析完成什么工作
  • 8.虚拟机字节码执行引擎
    • 什么是栈帧?
    • 栈帧存储了哪些信息?
    • Java方法调用的特点?
    • 什么静态解析?哪些方法的调用属于静态解析?
    • 静态分派?
    • 动态分派?
  • 12. Java内存模型与线程
    • 为什么要使用高速缓存?
    • 为什么要定义内存模型?
    • Java虚拟机内存模型的主要目标是什么?
    • Java虚拟机内存模型有哪些规定?
    • Volatile作用
    • Volatile修饰的变量线程安全吗?
  • 13. 线程安全和锁优化
    • 什么是线程安全?
    • 哪些方法可以实现或保证线程安全?
    • 什么是阻塞同步?
    • 什么是同步?
    • 什么是互斥?
    • synchronized的作用是什么?

2. JVM内存管理

2.2.Jvm 运行时内存区域2-18

线程私有区:程序计数器,虚拟机栈,本地方法栈
线程共享区:方法区,堆

程序计数器

记录当前字节码指令地址,可以看成当前线程执行字节码的行号指示器

虚拟机栈

描述运行时Java方法的内存模型,包括局部变量表,操作数栈,返回地址

Java堆

虚拟机启动时创建
Java堆是垃圾回收器管理的主要区域,因此也被成为Garbage Collected Heap

运行时常量池

方法区的一部分;用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量中。

2.3.虚拟机对象

对象的创建

  1. New对象时,先检查new指令的参数是否能在常量池中定位到一个类符号引用,并且检查这个符号引用代表是否已被加载,解析和初始化过。如果没有就必须执行类加载过程。
  2. 加载后开始分配内存,对象所需内存的大小在类加载完后便可确定。分配内存方式分为“指针碰撞”和“空闲列表”两种。选择那种方式由Java堆是否规整决定,而Java堆是否规整由垃圾收集器是否带有压缩整理功能决定。
    因为创建对象在虚拟机中是非常频繁的操作,所以分配内存还需考虑并发情况下的线程安全问题。
  3. 为分配的内存空间初始化为零值
  4. 做必要的设置(对象头),至此从虚拟机角度来看。对象已创建完毕
  5. 从Java代码角度来看,对象创建刚刚开始,还需要执行init方法,按照程序员的意愿初始化对象

3.2.对象存活判断方法

引用计数算法
可达性分析算法

7. 虚拟机类加载机制

什么是虚拟机类加载机制?

虚拟机类加载机制指的是描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析初始化,最终形成被虚拟机直接使用的Java类型的一个过程。

类的生命周期包括多少个阶段,分别是什么?

7个阶段,加载->验证->准备->解析->初始化->使用->卸载

类加载包括哪5个阶段?

加载->验证->准备->解析->初始化

连接包括哪3个阶段?

验证->准备->解析

哪5个生命周期阶段的顺序是确定的?

加载 验证 准备 初始化 卸载

为什么解析阶段的顺序是不确定的?

因为解析在某些情况下可以在初始化阶段后在开始,这是为了支持Java语言的运行时绑定,也称动态绑定

虚拟机规定了哪5种情况必须立即对类进行“初始化”?

  1. 遇到new, getstatic, putstatic或invokestatic 4条指令时
  2. 使用java.lang.reflect对类进行反射调用时
  3. 当初始化一个类时,如果父类还未初始化,必须先触发父类初始化
  4. 当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会初始化该主类
  5. 使用1.7jdk时,如果java.lang.invode.MethodHandle实例最后的解析结果REF_getStatic, Ref_putstatic, Ref_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化

类加载中的加载完成哪些工作?

  1. 通过一个类的全限定名来获取定义此类的二进制字节流
  2. 将这个字节流所代表的静态存储结构转换为方法区运行时数据结构
  3. 在内存中生成一个代表该类的java.lang.Class对象,作为该类的各种数据在方法区对外的访问入口

类加载中的验证完成什么工作

对Class文件字节流中的信息进行校验,已确保符合虚拟机要求,不会危害虚拟机的安全。主要完成4个阶段的检验动作:
文件格式验证,元数据验证,字节码验证,符号引用验证

解析完成什么工作

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
什么是符号引用:描述所引用目标的一组符号,可以是任何形式的字面量,只要使用时可以无歧义的定位到目标即可。
直接引用:直接指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。

8.虚拟机字节码执行引擎

什么是栈帧?

栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟运行时数据区的虚拟机栈的栈元素。

栈帧存储了哪些信息?

局部变量表,操作数栈,动态连接,方法返回地址等信息,在编译程序代码的时候,栈帧需要多大的局部变量表,多深的操作数栈都已经完全确定了,并且写入到方法表的code属性中

Java方法调用的特点?

方法调用阶段唯一的任务就是确定被调用方法的版本,即调用哪个方法。Class文件的编译不包含传统编译中的链接步骤,一切方法调用在Class文件里边存储的都只是符号引用,而不是方法在实际运行时内存布局的入口地址(直接引用)。这个特性给Java带来了更强大的动态扩展能力,但也使得Java方法调用过程变得相对复杂,需要在类加载期间或者运行时确定目标方法的直接引用

什么静态解析?哪些方法的调用属于静态解析?

Invokestatic, invokespecial静态方法,final方法

静态分派?

方法重载,编译期间确定方法调用

动态分派?

方法重写,invokevirtual, 运行时确定

12. Java内存模型与线程

为什么要使用高速缓存?

为什么要定义内存模型?

Java虚拟机内存模型的主要目标是什么?

Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中讲变量存储到内存和从内存中取出变量这样的底层细节。

Java虚拟机内存模型有哪些规定?

  1. 所有变量都存储在主内存中。
  2. 每条线程有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取,赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量。
  3. 不同的线程之间无法直接访问对方工作内存的变量,线程间变量值的传递均需要通过主内存来完成。

Volatile作用

  1. 线程对变量的更新,对其他线程来说是可见的。因为被volatile修饰的变量,对其更新时会立即同步到主内存,当线程需要使用变量时,也会从主内存中直接读取最新的值。
  2. 禁止代码重排序

Volatile修饰的变量线程安全吗?

不一定。虽然Volatile修饰的变量能够保证线程能够得到当前最新的变量值,但是如果运算的结果依赖变量的当前值,由于Java代码变量运算的非原子性,当前最新的变量值读到工作内存后但未做运算,变量可能被其他线程再次修改的可能,此时的变量值就是过期的数据,所以会出现线程不安全问题

13. 线程安全和锁优化

什么是线程安全?

共享对象在被多个线程并发访问处理时,总是能得到正确的结果

哪些方法可以实现或保证线程安全?

  1. 互斥同步(阻塞同步)
  2. 非阻塞同步

什么是阻塞同步?

多个线程的同步时会进行线程的阻塞和唤醒,这也是互斥同步所带来的性能问题

什么是同步?

多个线程在并发访问共享数据时,保证共享数据在同一时刻只被一个线程使用。

什么是互斥?

互斥是实现同步的一种手段,临界值,互斥量,信号量都是主要的互斥实现手段。

synchronized的作用是什么?

synchronized是Java实现互斥同步的最基本方法。Synchronized关键字经过编译之后,会在同步块前后分别形成monitorenter和monitorexit这两个字节码指令。这两个指令都需要一个引用类型参数来指明要锁定和解锁的对象。Synchronized同步块对同一条线程来说是可重入的,不会出现自己把自己缩写的问题。其次,同步块在已进入的线程执行完之前,会阻塞后面其他线程的进入。

你可能感兴趣的:(JVM,读书笔记)