JVM总结

102 阅读3分钟

01-JVM基本常识

  • 什么是JVM?广义上的JVM是指一种规范,狭义上的JVM指的是Hotspot类的虚拟机实现。
  • Java语言与JVM的关系:Java语言编写程序生成class字节码在JVM虚拟机里执行。其他语言也可以,比如Scala、Groovy。
  • 学习JVM主要学啥?类加载子系统 --> 运行时数据区 --> 一个对象的一生 --> GC垃圾收集器。
  • 学了JVM可以干啥?JVM调优,底层能力决定上层建筑。

02-类加载子系统

  • 类加载四个时机:1. new、getstatic、putstatic、invokestatic。2. 反射。3. 初始化子类发现父类没有初始化时。4. main函数的类。
  • 类加载主要过程:加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载。
  • 类加载主要做了三件事:
    1. 全限定名称 ==> 二进制字节流加载class文件。
    2. 字节流的静态数据结构 ==> 方法区的运行时数据结构。
    3. 创建字节码Class对象。
  • 可以从哪些途径加载字节码:Jar、war、JSP生成的class、数据库中二进制字节流、网络中二进制字节流、动态代理生成的二进制字节流。
  • 类加载器有哪些?启动类加载器BootstrapClassLoader、扩展类加载器ExtensionClassLoader、应用类加载器ApplicationClassLoader、自定义类加载器UserClassLoader。
  • 检查顺序自底向上,加载顺序自顶向下。
  • 什么是双亲委派?当一个类加载器收到加载任务,会先交给其父类加载器去加载。
  • 为何要打破双亲委派?父类加载器加载范围受限,无法加载的类需要委托子类加载器去完成加载。

03-运行时数据区

  • 堆:JVM启动时创建的最大的一块内存区域,用于存储对象、数组、运行时常量池都在这里。
  • 内存划分:Eden、2个Survivor、老年代。
  • 为什么要划分新生代与老年代?基于分代收集理论里的量大假说,弱分代和强分代假说,提升垃圾收集的效率。
  • 内存模型变迁史:JDK1.7 ---取消永久代,多了元空间---> JDK1.8 ---取消新生代与老年代物理划分---> JDK1.9。
  • 虚拟机栈:栈空间为线程私有,每个线程都会创建栈内存,生命周期与线程相同。线程内的栈内存占满了会出现StackOverflowError。
  • 栈帧是什么?栈帧(Stack Frame)是用于支持虚拟机进行方法执行的数据结构。
  • 本地方法栈:与虚拟机栈类似,区别在于本地方法栈为本地方法服务,也就是native方法。
  • 方法区:方法区的实现有两种:永久代(PermGen)、元空间(Metaspace)。
  • 方法区存什么数据?类型信息、方法信息、字段信息、类变量信息、方法表、指向类加载器的引用、指向Class实例的引用。
  • 永久代和元空间有什么区别?
    • 存储位置不同。
    • 存储内容不同。
  • 为什么要使用元空间来替换永久代?基于性能、稳定性、GC垃圾收集的复杂度考虑,当然也有Oracle收购了Java原因。
  • 字符串常量池
    • 三种常量池:class常量池、运行时常量池、字符串常量池。
    • 字符串常量池如何存储数据?使用哈希表【哈希冲突,哈希碰撞...】。
    • 字符串常量池如何查找字符串?类似于HashMap。
  • 程序计数器
    • 存储什么数据?当前线程执行时的字节码指令地址。
    • 为什么需要程序计数器?因为系统的上下文切换。
  • 直接内存
    • 相对堆内存,直接内存申请空间更耗时。
    • 直接内存IO读写的性能要优于普通的堆内存。

学习:Java 业务开发常见错误 100 例学习笔记