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函数的类。
- 类加载主要过程:加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载。
- 类加载主要做了三件事:
- 全限定名称 ==> 二进制字节流加载class文件。
- 字节流的静态数据结构 ==> 方法区的运行时数据结构。
- 创建字节码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 例学习笔记