尚硅谷 宋红康 JVM教程 学习笔记
https://www.bilibili.com/video/BV1PJ411n7xZ
ppt地址:
https://download.csdn.net/download/wei198621/14040543
P01-JVM内存与垃圾回收篇概述 09:34
P02-如何看待Java上层技术与JVM 20:17
P03-为什么要学习JVM 05:14
P04-面向人群和课程特点 10:15
P05-官方规范下载与参考书目 08:30
P06-跨平台的语言Java和跨语言的平台JVM 15:22
P07-字节码与多语言混合编程 06:25
P08-Java及JVM历史上的重大事件 14:10
P09-虚拟机与Java虚拟机介绍 08:59
P10-JVM的位置 03:44
P11-JVM的整体结构 06:24
P12-Java代码执行流程 05:17
P13-区分栈的指令集架构和寄存器的指令集架构 14:28
P14-JVM的生命周期 11:11
P15-SUN Classic VM的介绍 09:15
P16-Exact VM的介绍 03:18
P17-HotSpot VM的介绍 05:38
P18-JRockit VM的介绍 04:33
P19-IBM J9 VM的介绍 05:37
P20-KVM、CDC、CLDC的介绍 03:05
P21-Azul VM和BEA Liquid VM的介绍 03:04
P22-Apache Harmony的介绍 02:53
P23-Microsoft JVM和TaobaoJVM 05:34
P24-Dalvik VM及其他虚拟机的介绍 05:04
P25-Graal VM的介绍 03:14
P26-内存结构概述 08:44
P27-概述类的加载器及类加载过程 09:38
P28-类的加载过程一:Loading 04:33
P29-类的加载过程二:Linking 09:42
P30-类的加载过程三:Initialization 22:31
P31-几种类加载器的使用体会 13:23
P32-引导类、扩展类、系统类加载器的使用及演示 11:49
P33-为什么需要用户自定义类加载器及具体实现 08:19
P34-ClassLoader的常用方法及获取方法 05:30
P35-双亲委派机制的工作原理及演示 13:23
P36-双亲委派机制的优势 05:23
P37-沙箱安全机制 02:08
P38-类的主动使用与被动使用等 06:44
P39-运行时数据区内部结构 16:34
P40-JVM中的线程说明 05:34
P41-PC寄存器概述 11:04
P42-PC寄存器的使用举例 10:27
P43-解决PC寄存器两个面试问题 09:42
P44-虚拟机栈的主要特点 22:21
P45-虚拟机栈的常见异常与如何设置栈大小 11:43
P46-栈的存储结构和运行原理 25:34
P47-栈桢的内部结构 07:38
P48-局部变量表结构的认识 16:14
P49-字节码中方法内部结构的剖析 13:24
P50-变量槽slot的理解与演示 14:02
P51-静态变量与局部变量的对比及小结 09:01
P52-操作数栈的特点 11:43
P53-涉及操作数栈的字节码指令执行分析 16:11
P54-栈顶缓存技术 08:56
P55-动态链接的理解与常量池的作用 18:24
P56-方法的绑定机制:静态绑定与动态绑定 16:03
P57-4种方法调用指令区分非虚方法与虚方法 17:41
P58-invokedynamic指令的使用 11:15
P59-方法重写的本质与虚方法表的使用 15:35
P60-方法返回地址的说明 14:18
P61-栈桢中的一些附加信息 00:57
P62-虚拟机栈的5道面试题 23:19
P63-本地方法接口的理解 18:14
P64-本地方法栈的理解 08:17
P65-JVM学习路线与内容回顾 14:35
P66-堆空间的概述_进程中堆的唯一性 15:28
P67-堆空间关于对象创建和和GC的概述 17:38
P68-堆的细分内存结构 12:59
P69-堆空间大小的设置和查看 21:29
P70-OOM的说明与举例 09:40
P71-新生代与老年代中相关参数的设置 20:37
P72-图解对象分配的一般过程 18:25
P73-对象分配的特殊情况 06:38
P74-代码举例与JVisualVM演示对象的分配过程 05:38
P75-常用优工具概述与Jprofiler的演示 04:01
P76-MinorGC、MajorGC和FullGC的对比 17:26
P77-GC举例与日志分析 09:28
P78-体会堆空间分代的思想 05:09
P79-总结内存分配策略 12:56
P80-堆空间为每个线程分配的TLAB 09:55
P81-小结堆空间的常用参数设置 18:45
P82-通过逃逸分析看堆空间的对象分配策略 18:43
P83-代码优化之栈上分配 07:46
P84-代码优化之同步省略 04:58
P85-代码优化之标量替换 06:49
P86-代码优化及堆的小结 06:31
P87-方法区概述_栈堆方法区间的交互关系 11:42
P88-方法区的基本理解 17:27
P89-Hotspot中方法区的演进 09:37
P90-设置方法区大小的参数 14:52
P91-OOM:PermGen和OOM:Metaspace举例 09:58
P92-方法区的内部结构1 21:14
P93-方法区的内部结构2 08:13
P94-class文件中常量池的理解 18:12
P95-运行时常量池的理解 06:38
P96-图示举例方法区的使用 16:45
P97-方法区在jdk6、jdk7、jdk8中的演进细节 25:21
P98-StringTable为什么要调整位置 05:27
P99-如何证明静态变量存在哪 11:15
P100-方法区的垃圾回收行为 11:10
P101-运行时数据区的总结与常见大厂面试题说明 06:25
P102-对象实例化的几种方式 10:05
P103-字节码角度看对象的创建过程 06:12
P104-对象创建的六个步骤 22:07
P105-对象的内存布局 11:00
P106-对象访问定位 07:48
P107-直接内存的简单体验 07:53
P108-使用本地内存读写数据的测试 07:49
P109-直接内存的00M与内存大小的设置 10:44
P110-执行引擎的作用及工作过程概述 18:47
P111-Java程序的编译和解释运行的理解 10:11
P112-机器码_指令_汇编_高级语言理解与执行过程 15:40
P113-解释器的使用 11:00
P114-HotspotVM为何解释器与JIT编译器并存 17:32
P115-热点代码探测确定何时JIT 16:53
P116-Hotspot设置模式_C1与C2编译器 15:20
P117-Graal编译器与AOT编译器 07:41
P118-String的不可变性 21:34
P119-String底层Hashtable结构的说明 15:57
P120-String内存结构的分配位置 09:46
P121-两个案例熟悉String的基本操作 11:20
P122-字符串拼接操作的面试题讲解 14:01
P123-字符串变量拼接操作的底层原理 17:21
P124-拼接操作与append操作的效率对比 10:01
P125-intern()的理解 11:46
P126-new String()到底创建了几个对象 12:25
P127-关于intern()的面试难题 13:40
P128-面试的拓展问题 06:21
P129-intern()的课后练习1 08:05
P130-intern()的课后练习2 04:04
P131-intern()的空间效率测试 12:31
P132-StringTable的垃圾回收测试 05:32
P133-G1垃圾收集器的String去重操作 08:38
P134-垃圾回收相关章节的说明 08:18
P135-什么是GC,为什么需要GC 19:45
P136-了解早期垃圾回收行为 04:08
P137-Java自动内存管理介绍 08:11
P138-垃圾回收相关算法概述 09:17
P139-引用计数算法的原理及优缺点 13:47
P140-Java代码举例_Python的引用计数实施方案 08:25
P141-可达性分析算法与GC Roots 12:41
P142-对象的finalization机制 18:34
P143-代码演示可复活的对象 07:37
P144-使用MAT查看GC Roots 13:42
P145-使用JProfiler进行GC Roots溯源 06:38
P146-使用JProfiler分析OOM 03:32
P147-标记-清除算法原理及优缺点 16:08
P148-复制算法原理及优缺点 14:01
P149-标记-压缩算法原理及优缺点 11:16
P150-不同指标上对比三种算法 04:38
P151-分代收集算法的说明 12:36
P152-增量收集算法原理及优缺点 09:14
P153-分区算法的说明 03:59
P154-垃圾回收相关概念的概述 10:11
P155-System.gc()的理解 08:47
P156-手动gc理解不可达对象的回收行为 10:18
P157-内存溢出的分析 11:40
P158-内存泄漏的分析 13:04
P159-StopTheWorld事件的理解 10:57
P160-程序的并行与并发 06:33
P161-垃圾回收的并行与并发 03:39
P162-安全点与安全区域的说明 09:01
P163-Java中几种不同引用的概述 10:54
P164-强引用:不回收 06:35
P165-软引用:内存不足即回收 16:30
P166-弱引用:发现即回收 08:02
P167-虚引用:对象回收跟踪 13:29
P168-终结器引用的介绍 01:45
P169-垃圾回收器章节概览 05:07
P170-垃圾回收器的分类 15:31
P171-GC性能指标的整体说明 09:16
P172-吞吐量与暂停时间的对比说明 09:41
P173-垃圾回收器的发展迭代史 17:06
P174-垃圾回收器的组合关系 12:49
P175-如何查看默认的垃圾回收器 06:22
P176-Serial与Serial Old垃圾回收器的介绍 08:54
P177-如何设置使用Serial垃圾回收器 04:43
P178-ParNew垃圾回收器的介绍 07:22
P179-如何设置使用ParNew垃圾回收器 03:58
P180-Parallel与Parallel Old垃圾回收器的介绍 08:56
P181-Parallel垃圾回收器的相关参数设置 17:29
P182-CMS垃圾回收器概述与工作原理 12:45
P183-CMS的特点与弊端分析 15:58
P184-CMS垃圾回收器的参数设置 09:06
P185-CMS的小结及后续JDK版本中的变化 03:45
P186-认识G1垃圾回收器 14:52
P187-G1垃圾回收器的优势和不足 20:24
P188-G1的参数设置 09:12
P189-G1在生产环境的适用场景 03:58
P190-region的使用介绍 11:36
P191-G1垃圾回收器的主要回收环节 08:14
P192-记忆集与写屏障 08:24
P193-G1垃圾回收过程的详细说明 24:16
P194-G1垃圾回收的优化建议 04:11
P195-7种经典的垃圾回收器总结与调优建议 14:02
P196-常用的显示GC日志的参数 13:30
P197-GC日志中垃圾回收数据的分析 09:03
P198-举例说明日志中堆空间数据如何解读 10:16
P199-日志分析工具的使用 07:29
P200-新时期的Epsilon和Shenandoah垃圾回收器 13:21
P201-革命性的ZGC的性能介绍 09:03
P202-其他的厂商的垃圾回收器 01:41
P203-最后寄语 09:42
P204-JVM中篇内容概述 11:51
P205-字节码文件的跨平台性 13:12
P206-了解Java的前端编译器 08:30
P207-透过字节码看代码执行细节举例1 11:15
P208-透过字节码看代码执行细节举例2 03:51
P209-透过字节码看代码执行细节举例3 11:52
P210-解读Class文件的三种方式 15:47
P211-Class文件本质和内部数据类型 15:58
P212-Class文件内部结构概述 08:00
P213-字节码数据保存到excel中的操作 07:28
P214-Class文件的标识:魔数 06:33
P215-Class文件版本号 09:40
P216-常量池概述 05:50
P217-常量池计数器 03:53
P218-常量池表中的字面量和符号引用 15:49
P219-解析得到常量池中所有的常量 16:34
P220-常量池表数据的解读1 10:31
P221-常量池表数据的解读2 10:53
P222-常量池表项数据的总结 08:13
P223-访问标识 08:20
P224-类索引、父类索引、接口索引集合 07:41
P225-字段表集合的整体理解 08:13
P226-字段表数据的解读 12:01
P227-方法表集合的整体理解 06:51
P228-方法表数据的解读 10:48
P229-属性表集合的整理理解 04:47
P230-方法中Code属性的解读 13:44
P231-LineNumberTable和LocalVariableTable属性的解读 21:34
P232-SourceFile属性的解读 07:45
P233-Class文件结构的小结 03:42
P234-javac -g操作的说明 13:21
P235-javap主要参数的使用 21:16
P236-javap解析得到的文件结构的解读 21:19
P237-javap使用小结 05:05
P238-字节码指令集的概述 14:33
P239-指令与数据类型的关系及指令分类 10:11
P240-加载与存储指令概述 08:12
P241-再谈操作数栈与局部变量表 07:24
P242-局部变量压栈指令 08:44
P243-常量入栈指令 14:13
P244-出栈装入局部变量表指令 14:25
P245-算术指令及举例 20:37
P246-算法指令再举例 06:23
P247-彻底搞定++运算符 08:15
P248-比较指令的说明 02:46
P249-宽化类型转换 17:32
P250-窄化类型转换 18:50
P251-创建类和数组实例的指令 16:11
P252-字段访问指令 11:21
P253-数组操作指令 12:14
P254-类型检查指令 04:18
P255-方法调用指令 15:35
P256-方法返回指令 07:51
P257-操作数栈管理指令 19:20
P258-比较指令 08:29
P259-条件跳转指令 23:00
P260-比较条件跳转指令 08:16
P261-多条件分支跳转指令 14:11
P262-无条件跳转指令 15:33
P263-抛出异常指令 14:07
P264-异常处理与异常表 24:25
P265-同步控制指令 24:14
P266-类的生命周期概述 15:57
P267-加载完成的操作及二进制的获取方式 07:24
P268-类模型与Class实例的位置 08:19
P269-链接之验证环节 13:41
P270-链接之准备环节 11:15
P271-链接之解析环节 11:58
P272-初始化过程与类初始化方法 08:46
P273-初始化阶段赋值与准备阶段赋值的对比 26:33
P274-类初始化方法clinit()的线程安全性 07:02
P275-何为类的主动使用和被动使用 04:03
P276-类的主动使用1 08:00
P277-类的主动使用2 13:54
P278-类的主动使用3 11:43
P279-类的主动使用4 07:46
P280-类的被动使用 14:11
P281-类的使用介绍 04:59
P282-类的卸载相关问题 15:47
P283-类加载器的概述 12:35
P284-命名空间与类的唯一性 15:57
P285-类的加载器的分类 07:32
P286-引导类加载器的说明 09:02
P287-扩展类加载器的说明 06:17
P288-系统类加载器的说明 04:53
P289-用户自定义类加载器的说明 02:09
P290-测试不同类使用的类加载器 09:10
P291-ClassLoader与Launcher的初步剖析 11:50
P292-ClassLoader的源码解析1 15:04
P293-ClassLoader的源码解析2 07:08
P294-ClassLoader子类的结构剖析 05:16
P295-双亲委派机制的优势与劣势 22:02
P296-三次双亲委派机制的破坏 15:32
P297-热替换的代码实现 07:16
P298-沙箱安全机制 05:36
P299-自定义类加载器的好处和应用场景 05:43
P300-自定义类加载器的代码实现 15:57
P301-Java9的新特性 15:13
面试的需要(BATJ,TMD,PKQ)
中高级程序要必备技能
追求极客精神:
理论时间 大于 代码时间
图解
oracle 官方地址 : https://docs.oracle.com/javase/specs/
周志明: 深入理解JAVA虚拟机
oracle 自己发布JAVA虚拟机 hotSpot
https://www.tiobe.com/tiobe-index/
从JAVA7开始,JAVA虚拟机的设计者通过JSR-292规范实现“Java虚拟机平台上运行非Java语言编写的程序”
java7----2011年7月发布
java 不是最强大的语言,但是JVM是最强大的虚拟机。
Java虚拟机从“JAVA虚拟机”向“JVM虚拟机”发展。
自己动手写JAVA虚拟机----资料介绍—据说20天左右
1990, JamesGosling 命名Oak,后改名Java
1995, Java首次公开亮相
1996, Jdk1.0 发布
1998, jdk1.2
2000, jdk1.3
2002, jdk1.4 (微软的.net发布)
2004, jdk 1.5 jdk 1.5 改名 JavaSE 5.0 (5.0是很大的改动)
2006, jdk 6
2007, Cljure
2008, Oracle收购BEA,得到 JRocket 虚拟机
2009, Twitter 改版 ,将程序从Ruby 改为 Scala
2010, Oracle 收购 Sun(74亿美元),Oracle 获得了HotSpot虚拟机 ,JCP组织进项管理java语言
2011 jdk7 {启用G1垃圾回收器}
2017 jdk9
2018 jdk11 {启用ZGC垃圾回收器} , Android 的Java 侵权案判决, Google赔偿 Oracle 88亿美元(注意收购时候用了74亿美元)
虚拟机: 系统虚拟机,程序虚拟机
系统虚拟机:VMWare
程序虚拟机:Java虚拟机 (JVM: Java Virtual Machine) ,之前jvm运行的是JAVA字节码,现在jvm运行的字节码有多种,Scala ,Kotlin ,Groovy 等
方法区、堆: 多线程共享
栈、本地方法栈、程序计数器: 每个线程独享一份
java的JVM是基于栈的架构,跨平台性好,指令集小,指令多,执行性能比基于寄存器架构方式差。
javap -v StackStruTest.class 反编译字节码文件 指令
C:\workspace\workspace_idea\jvmByAtguigu\chapter01\target\classes\com\tiza\jvm>javap -v StackStruTest.class
public static void main(String[] args) {
int i = 2;
int j = 3;
int var10000 = i + j;
}
Code:
stack=2, locals=4, args_size=1
0: iconst_2 --------- 常量2
1: istore_1 --------- 放到操作数栈索引位置1
2: iconst_3 --------- 常量3
3: istore_2 --------- 放到操作数栈索引位置2
4: iload_1 --------- 加载 操作数栈索引位置1 也就是 i
5: iload_2 --------- 加载 操作数栈索引位置2 也就是 j
6: iadd --------- 求和
7: istore_3 --------- 将结果k 保存在 操作数栈索引位置3
8: return ---------
LineNumberTable:
虚拟机启动 执行 退出
启动:
执行: 执行一个java程序的时候,实际执行的是一个叫做JAVA虚拟机的进程。
退出:
Sun Classic VM :
世界第一款商用Java虚拟机,JDK1.4 的时候,完全被淘汰了。
只提供解释器,
现在的hotspot内置了此虚拟机。
hotspot VM
执行引擎:编译器+JIT(及时编译器)+垃圾回收器
Exact VM jdk1.2 时候 Sun 提供
编译器 与 解释器 混合使用工作模式
HotSpot:
HotSpot 是由 Longview Technologies 这家公司设计的
1997年SUN公司收购了这家公司,2009年sun这家公司被oracle收购。
JDK1.3 的时候,Hotspot VM 成为默认虚拟机。
HotSpot 占有绝对的市场定位,称霸武林。
EBA 的JRockit : 专注于服务器端应用,不关注程序的相应时间,因此,JRockit内部不包含解释器实现。JRockit JVM 是世界最快的JVM .
2008年, BEA 被oracle 收购了,
IBM Technology for Java Virtual Machine == IT4J = J9
2017年,IBM发布了开源J9 VM ,命名OpenJ9 ,交给Eclipse基金会管理。
注意是开源了J9 VM ,并没有开源J9 的全部(JDK>JRE>JVM)
Azul VM
BEA Liquid VM: 已经终止研发
Apache Harmony: IBM 和 Intel 联合开发开源JVM 。在. jdk 1.5 ,jdk 1.6 平台可用 。
Microsoft JVM: 微软在自己的机器上开发Microsoft JVM ,1997年sun公司告微软的Microsoft 侵权,微软赔钱,后来取消了Microsoft JVM 项目。
TaoBaoJVM: 升级的hotspot JVM .
Android系统使用的虚拟机,Dalvik VM 只能称作虚拟机,不能称作“JAVA虚拟机”,因为它没有遵守JAVA虚拟机规范
它不能直接运行java的class文件
它是基于寄存器架构的,不是JVM的栈架构
执行的是编译后的dex(Dalvik Executable)文件。执行效率比较高。
android 5.0 支持 ART VM 和 Dalvik VM .
如果有一天HotSpot被取代,Graal VM 希望最大。
Graal 兼容性比较强
方法区:
C:\workspace\workspace_idea\jvmByAtguigu\chapter01\target\classes\com\tiza\jvm>javap -v StackStruTest.class
在本地磁盘的 .class file 文件,加载到JVM中,放在方法区。
类的加载过程
加载–》 链接–》 初始化
1.获取此类的二进制流
2.将此流放到方法区
3.在内存中生成一个代表此类的java.lang.Class对象,作为方法区这个类的各种数据访问入口。
todo … 20200103
下载安装 jclasslib Bytecode Viewer
package com.tiza.jvm.chapter02;
/**
* @author leowei
* @date 2021/1/4 - 23:47
*/
public class ClassLoaderTest {
public static void main(String[] args) {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("systemClassLoader = " + systemClassLoader); //sun.misc.Launcher$AppClassLoader@14dad5dc
//获取其上层:扩展类加载器
ClassLoader extClassLoader = systemClassLoader.getParent();
System.out.println("extClassLoader = " + extClassLoader); //sun.misc.Launcher$ExtClassLoader@28d93b30
// 获取上层类加载器
ClassLoader parent = extClassLoader.getParent();
System.out.println("parent = " + parent); // null 实际是bootStrapLoader ,此类由虚拟机定义
//用户自定义类 的 classloader
ClassLoader userDefineClsClassLoader = ClassLoaderTest.class.getClassLoader();
System.out.println("userDefineClsClassLoader = " + userDefineClsClassLoader); //sun.misc.Launcher$AppClassLoader@14dad5dc
//String类 使用引导类加载器进行加载 ---> java 的核心类库 都是用 Bootstrap引导类加载器加载的
ClassLoader strClassLoader1 = String.class.getClassLoader();
System.out.println("strClassLoader1 = " + strClassLoader1); //null
}
}
扩展类加载器加载 jre/lib/ext 目录下的类库
package com.tiza.jvm.chapter02;
import sun.misc.Launcher;
import sun.security.ec.CurveDB;
import java.net.URL;
import java.security.Provider;
/**
* @author leowei
* @date 2021/1/5 - 0:12
*/
public class ClassLoaderTest02 {
public static void main(String[] args) {
System.out.println("************** 启动类加载器 *************");
URL[] urls = Launcher.getBootstrapClassPath().getURLs();
for (URL element : urls) {
System.out.println(element.toExternalForm());
}
//从上面路径中随意选择一个类,看看他的类加载器是什么:引导类加载器
ClassLoader classLoader = Provider.class.getClassLoader();
System.out.println("classLoader = " + classLoader); // null
System.out.println("************ 扩展类加载器 *************");
String extDirs = System.getProperty("java.ext.dirs");
for (String path : extDirs.split(";")) {
System.out.println("path = " + path);
}
//从上面路径中随意选择一个类,看看他的类加载器是什么:引导类加载器
ClassLoader classLoader1 = CurveDB.class.getClassLoader();
System.out.println("classLoader1 = " + classLoader1); // sun.misc.Launcher$ExtClassLoader@330bedb4
}
}
高深技术,暂时 无需自己实现
获取ClassLoader的途径
package com.tiza.jvm.chapter02;
/**
@author leowei
@date 2021/1/5 - 0:36
*/
public class ClassLoaderTest03 {
public static void main(String[] args) {
// 1
ClassLoader classLoader = null;
try {
classLoader = Class.forName("java.lang.String").getClassLoader();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("classLoader = " + classLoader); // null
// 2.
ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader();
System.out.println("classLoader1 = " + classLoader1);
//3.
ClassLoader classLoader2 = ClassLoader.getSystemClassLoader();
System.out.println("classLoader2 = " + classLoader2);
// 4.
ClassLoader classLoader3 = classLoader2.getParent();
System.out.println("classLoader3 = " + classLoader3);
/*
classLoader = null
classLoader1 = sun.misc.Launcher A p p C l a s s L o a d e r @ 14 d a d 5 d c c l a s s L o a d e r 2 = s u n . m i s c . L a u n c h e r AppClassLoader@14dad5dc classLoader2 = sun.misc.Launcher AppClassLoader@14dad5dcclassLoader2=sun.misc.LauncherAppClassLoader@14dad5dc
classLoader3 = sun.misc.Launcher$ExtClassLoader@28d93b30
*/
}
}
没有听懂,
自定义一个java.lang.String 的类,(此类同jdk中的包名及类名),正常执行,不会报错,执行的过程是,String类加载到 Class Loader 中,
step1: Application ClassLoader 委托 — (低优先级) 如果前两个都不Load ,就我来执行
step2: Extension ClassLoader 委托 ----(中优先级)如果此 ClassLoader 能够响应对应的包,就执行响应,如果不行,交给 Application ClassLoader
step3: BootStrap ClassLoader ------(高优先级)如果 此ClassLoader 能够响应对应的包,就执行响应,如果不行,交给 Extension ClassLoader
package java.lang;
/**
* @author leowei
* @date 2021/1/5 - 23:06
* 由于 java.lang 是由 启动类加载器进行加载, 加载的时候发现没有main函数,所以报如下错误
* java.lang.SecurityException: Prohibited package name: java.lang
* 双亲委派机制优势
* 1.避免类的重复加载
* 2.保护程序安全,放置核心API 被随意篡改
*/
public class LeoStart {
public static void main(String[] args) {
System.out.println("------");
}
}
java虚拟机定义了若干程序运行期间会使用到的运行时数据区,
其中有一些会随着虚拟机的启动而创建,随着虚拟机退出而销毁。
另外一些则与线程一一对应,这些线程对应的数据区域会随着线程开始和结束而创建和销毁。
每个线程: 独立包括程序计数器,栈,本地栈
线程间共享: 堆、对外内存(元空间、代码缓存、永久代)
https://docs.oracle.com/javase/specs/jvms/se8/html
https://www.oracle.com/downloads/
https://www.oracle.com/java/technologies/javase-downloads.html
https://docs.oracle.com/javase/8/docs/
https://docs.oracle.com/javase/specs/index.html
https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.1
PC Register 用于存储程序当前运行位置,及将要运行的位置,也叫程序钩子
演示此段代码,看效果
package com.tiza.jvm.chapter04;
/**
* @author leowei
* @date 2021/1/6 - 21:02
*/
public class PCRegisterTest {
public static void main(String[] args) {
int i=10;
int j=20;
int k=i+j;
String str="abc";
System.out.println(i);
System.out.println(k);
}
}
1.使用PC寄存器存储字节码指令地址有什么用?
2.为什么使用PC寄存器记录当前线程的执行地址?
并行:
并发:
(虚拟机架构两种方式: 基于栈的方式,基于寄存器的方式 )
由于跨平台性的设计,Java的指令都是根据栈来设计的,不同平台CPU架构不同,所以不能设计为基于寄存器的。
优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令。
JVM 中的异常: OutOfMemoryError , StackOverflowError
https://docs.oracle.com/en/java/javase/11/tools/java.html#GUID-3B1CE181-CD30-4178-9602-230B800D4FAE
package com.tiza.jvm.chapter05;
/**
* @author leowei
* @date 2021/1/6 - 22:20
*
* 自循环调用会报 java.lang.StackOverflowError 的异常
* 默认栈大小情况下 调用次数 11406
* 设置虚拟机栈大小 256k 调用次数 2467 (-Xss256k)
*
*
*/
public class StackErrorTest {
private static int count=1;
public static void main(String[] args) {
System.out.println(count);
count++;
main(args);
}
}
package com.tiza.jvm.chapter05;
/**
* @author leowei
* @date 2021/1/6 - 23:01
*/
public class StackFrameTest {
public static void main(String[] args) {
StackFrameTest stackTest = new StackFrameTest();
stackTest.method1();
}
// 注意使用 javap -v ***.class 反编译 看效果 ,需要为public 方法,原理未知
public void method1() {
System.out.println("method1() 开始执行... ");
method2();
System.out.println("method1() 执行结束... ");
}
// 注意使用 javap -v ***.class 反编译 看效果 ,需要为public 方法,原理未知
public int method2() {
System.out.println("method2() 开始执行... ");
int i = 10;
i = (int) method3();
System.out.println("method2() 执行结束... ");
return i;
}
// 注意使用 javap -v ***.class 反编译 看效果 ,需要为public 方法,原理未知
public double method3() {
System.out.println("method3() 开始执行... ");
double j = 20.0;
System.out.println("method3() 执行结束... ");
return j;
}
}
Stack Frame 包含五个部分
LV:Local Variables 局部变量表
OS: Operand Stack 操作数栈 (表达式栈)
DL:Dynamic Linking 动态链接库 (指向运行时常量池的方法引用)
RA:Return Address 方法返回地址 (方法正常退出或者异常退出的定义)
其他信息
Local variables : 局部变量表 也叫 局部变量数组 或者 本地变量表
package com.tiza.jvm.chapter05;
import java.util.Date;
/**
* @author leowei
* @date 2021/1/7 - 22:47
*/
public class LocalVariablesTest {
private int count=0;
public static void main(String[] args) {
LocalVariablesTest test = new LocalVariablesTest();
int num=10;
test.test1();
}
public LocalVariablesTest(){
}
public void test1(){
Date date = new Date();
String name1 = "atguigu.com";
test2(date,name1); //String info=
System.out.println(date+name1);
}
public String test2(Date dateP,String name2){
dateP =null;
name2="songhongkang";
double weight =130.5;
char gendar ='男';
return name2;
}
public void test4() {
int a = 0;
{
int b = 0;
b = a + 1;
}
//变量c,使用的是之前已经销毁的变量b占据的slot的位置
int c = a + 1;
}
}
todo … 20210108
方法的调用:
静态链接, 动态链接
早期绑定, 晚期绑定
非虚方法, 虚方法
虚拟机中的几个方法调用指令:
非虚方法: 静态方法、私有方法、final方法、实例构造器、父类方法 (总结private final static )
虚方法: 其他方法。。
java.lang.IllegalAccessError
java.lang.AbstractMethodError
方法返回地址: return address , 存放调用改方法的PC寄存器的值。
package com.tiza.jvm.chapter05;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
/**
* @author leowei
* @date 2021/1/9 - 8:40
*/
public class ReturnAddressTest {
public char methodChar(){
return 'a';}
public int methodInt(){
return 0;}
public long methodLong(){
return 0L; };
public float methodFloat(){
return 0.0f;}
public double methodDouble(){
return 0.0;}
public String methodString(){
return null;}
public Date methodDate(){
return null;}
static {
int i=10;
}
public void method2(){
try {
method1();
} catch (IOException e) {
e.printStackTrace();
}
}
public void method1() throws IOException{
FileReader fis = new FileReader("leavingTiza.txt");
char[] cBuffer =new char[1024];
int len;
while((len=fis.read(cBuffer)) != -1){
String str = new String(cBuffer, 0, len);
System.out.println(str);
}
fis.close();
}
}
最后8分钟的线程安全与否,搞不懂 。
栈溢出: StackOverflowError
通过-Xss设置栈的大小
Native Method: 一个java调用一个非Java代码接口 。
示例: java接口调用c语言类库
本地方法没有方法体。
Native Method Stack
java虚拟机栈 用于管理Java方法的调用, 本地方法栈用于管理本地方法的调用。
本地方法是用c c++ … 语言编写的
本地方法栈 ,方法区 : 是HotSpot虚拟机特有的,不是所有虚拟机都有这两个区域。
方法区与堆,都是进程共享的,一个进程对应一个 JVM 实例
一个进程中的多个线程共享 堆及方法区,
每个线程,有一组 虚拟机栈、本地方法栈、程序计数器
Java堆区在JVM启动的时候就创建了,其空间大小就确定了。是JVM管理的最大内存空间。堆内存大小是可以调节的。
C:\developer_tools\Java\jdk1.8.0_45\bin
…
文章太长了,转下一篇
尚硅谷 宋红康 JVM教程 狗剩学习笔记 02
https://blog.csdn.net/wei198621/article/details/112389917