为什么要学习java虚拟机

1、学习java虚拟机的本质,是了解java程序是如何被执行且优化的。这样一来,才可以从内部入手,达到高效编程的目的。与此同时,你也可以为学习更深层级、更为核心的java技术打好基础。

2、学习java虚拟机的好处

(一)可以针对自己的应用,最优化匹配运行参数。

(二)可以更好地规避虚拟机在使用中的bug,也可以更快地识别出java虚拟机中的错误。

(三)学习最前沿、最成熟的垃圾回收算法实现以及及时编译器的实现,对以后学习其他的代码托管技术很有帮助。

(四)虚拟机也可以运行其他语言,了解这些语言的通用体制,甚至让这些语言共享生态系统。

3、课程内容

(一)基本原理:剖析java虚拟机的运行机制,逐一介绍java虚拟机的设计决策以及工程实现。

(二)高效实现:探索java编译器,以及内嵌于java虚拟机中的及时编译器,更好理解java语言特性,继而写出简洁高效的代码。

(三)代码优化:介绍如何利用工具定位并解决代码中的问题,以及在已有工具不适用的情况下,如何打造专属轮子。

(四)虚拟机黑科技

第一节 Java代码是如何运行的?

为什么java要在虚拟机里运行?

语法复杂,抽象度高,在硬件上实现不现实。

转换思路:设计一个面向java语言特性的虚拟机,并通过编译器将java程序转换成该虚拟机所能识别的指令序列,也称java字节码(操作码都被固定为一个字节)。然后java虚拟机可以由硬件实现(一次编写,到处运行)

虚拟机附带托管环境(自动内存管理、垃圾回收、还提供诸如数组越界、动态类型、安全权限等动态检测)

java虚拟机具体是怎样运行java字节码的?

1、首先将编译成的class文件加载到java虚拟机中

2、在运行过程中,每当调用进入一个java方法,java虚拟机会在当前线程的java方法栈中生成一个栈帧,用以存放局部变量以及字节码的操作数。、

3、当退出当前的执行方法时( 不管正常返回还是异常返回),java虚拟机均会弹出当前线程的当前栈帧,并将之舍弃。

4、将字节码翻译成机器码。两种形式:(一)解释执行:逐条将字节码翻译成机器码并执行。(二)即时编译(JIT)将一个方法中包含的所有字节码编译成机器码后再执行。前者的优势在于无需等待编译,后者的优势在于实际运行速度更快。

对不常用的代码解释执行,对小部分热点代码及时编译。

第二节 java的基本类型

java虚拟机中的boolean类型

在java虚拟机规范中,boolean类型被映射成int类型。“true”被映射为整数1,“false”被映射为整数0。

public class Foo {
public static void main(String[] args) {
boolean 吃过饭没 = 2; // 直接编译的话 javac 会报错
if (吃过饭没) System.out.println(" 吃了 ");
if (true == 吃过饭没) System.out.println(" 真吃了 ");
}
}
# Foo.main 编译后的字节码
0: iconst_2 // 我们用 AsmTools 更改了这一指令
1: istore_1
2: iload_1
3: ifeq 14 // 第一个 if 语句,即操作数栈上数值为 0 时跳转
6: getstatic java.lang.System.out
9: ldc " 吃了 "
11: invokevirtual java.io.PrintStream.println
14: iload_1
15: iconst_1
16: if_icmpne 27 // 第二个 if 语句,即操作数栈上两个数值不相同时跳转
19: getstatic java.lang.System.out
22: ldc " 真吃了 "
24: invokevirtual java.io.PrintStream.println
27: return

上述程序运行只会打印“吃了”而不会打印“真吃了”,是因为对于java虚拟机来说,它看到的boolean类型,早已被映射为整数类型。因此,将原本声明为boolean类型的局部变量,赋值为出了0,1以外的整数值,在java虚拟机看来是“合法”的。

java基本类型

正无穷和负无穷分别是是0x7F800000和0xFF800000

0xF800001等对应NaN(Not-a-Number)

0x7FC00000为标准NaN,其他为不标准NaN。

NaN特性:除了“!=”始终返回true之外,所有其他比较结果都会返回false。

java类型的基本大小

栈帧有两个主要的组成部分

(一)局部变量区

在虚拟机规范中,局部变量区等价于一个数组,并且可以用正整数来所引。long、double值需要用两个数组单元来存储,boolean、byte、char、short和int在栈上占用的空间是一样的,引用类型也是一样的。(仅限于局部变量)

值读入字段或数组时相当于做了一次隐式掩码操作。(截取高位字节保证读入数据满足相应的字节要求)

boolean类型只读取最后一位读入字段或数组。

(二)字节码的操作数栈

java虚拟机的算术运算几乎全部依赖于操作栈。我们需要将堆中的boolean、byte、char以及short加载到操作栈上,而后将栈上的值当成int类型来运算。

对于boolean、char两个类型来说,加载伴随零扩展。加载时会被复制到int类型的低二字节,而高二字节会用0来填充。

对于byte、short这两个类型来说,加载伴随符号扩展。加载时会被复制到int类型的低二字节。然后根据正负高二字节用0或1填充。

java虚拟机是如何加载java类的

从class文件到内存中的类,按先后顺序需要经过加载、链接以及初始化三大步骤。

public class Foo {
static boolean boolValue;
public static void main(String[] args) {
boolValue = true; // 将这个 true 替换为 2 或者 3,再看看打印结果
if (boolValue) System.out.println("Hello, Java!");
if (boolValue == true) System.out.println("Hello, JVM!");
}
}

对于上述程序,当替换为2时候无输出,当替换为3时候打印HelloJava及HelloJVM。因为boolean的掩码处理是取低位最后一位,2取低位最后一位为0,3取低位最后一位为1。

java虚拟机是如何加载java类的?

加载

是指查找字节流,并且据此创建类的过程。对于数组类来说,是由java虚拟机直接生成。对于其他类来说,java虚拟机需要借助类加载器来完成查找字节流的过程。

启动类加载器没有java对象,在java中只能用null来指代。除了启动类加载器,其他的类加载器都是java.lang.ClassLoder的子类,因此有对应的java对象。这些类加载器需要先由另一个类加载器,比如说启动类加载器,加载至java虚拟机中,放能执行类加载。

双亲委派模型:每当一个类加载器接收到加载请求时,它会先将请求转发给父类加载器。在父类加载器没有找到所请求的类的情况下,该类加载器才会尝试去加载。

另外两个重要的类加载器是扩展类加载器和应用类加载器,均由java核心类库提供。

三个重要类加载器功能

1、启动类加载器负责加载最为基础最为重要的类。

2、扩展类加载器的父类是启动类加载器,扩展类加载器负责加载相对次要、但又通用的类。

3、应用类加载器的父类是扩展类加载器,它负责加载应用程序路径下的类。

在java虚拟机中,类的唯一性是由类加载器实例以及类的全名一同决定的。即便是同一串字节流,经由不同的类加载器加载,也会得到两个不同的类。

链接

是指将创建成的类合并至java虚拟机中,使之能够执行的过程。它可以分为验证、准备以及解析三个阶段。

(一)验证阶段

的目的,在于确保被加载类能够满足java虚拟机的约束条件。

(二)准备阶段

的目的是为被加载类的静态字段分配内存。部分java虚拟机还会构造其他跟类层次相关的数据结构,比如说用来实现虚方法的动态绑定方法表。在class文件被加载至java虚拟机之前,这个类无法知道其他类及其方法、字段所对应的具体地址,甚至不知道自己的方法、字段的地址。因此,每当需要引用这些成员时,java编译器会生成一个符号引用。

(三)解析阶段的目的,正是将这些符号引用解析成为实际引用。如果符号引用指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载。

初始化

如果要初始化一个静态字段,可以在声明时直接赋值,也可以在静态代码块中对其赋值。如果直接赋值的静态字段被final修饰,并且它的类型是基本类型或字符串时,那么该字段便会被java编译器标记成常量值,起初始化直接由java虚拟机完成。除此之外的直接赋值操作,以及所有静态代码块中的代码,则会被java编译器置于同一方法中,并把它命名为。类加载的最后一步是初始化,便是为标记为常量值的字段赋值,以及执行方法的过程。java虚拟机会通过加锁来确保,类的方法仅被执行一次。

类的初始化触发情况:

1、当虚拟机启动时,初始化用户指定的类。

2、当遇到用以新建目标类实例的new命令时,初始化new命令的目标类。

3、当遇到调用静态方法的指令时,初始化该静态方法所在的类。

4、党遇到访问静态字段的指令时,初始化·该静态字段所在的类。

5、子类的初始化会触发父类的初始化。

6、如果一个接口定义了default方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化。

7、使用反射API对某个类进行反射调用时,初始化这个类。

8、当初次调用MethodHandle实例时,初始化该MethodHandle指向的方法所在的类。

public class Singleton {
private Singleton() {}
private static class LazyHolder {
static final Singleton INSTANCE = new Singleton();
static {
System.out.println("LazyHolder.<clinit>");
}
}
public static Object getInstance(boolean flag) {
if (flag) return new LazyHolder[2];
return LazyHolder.INSTANCE;
}
public static void main(String[] args) {
getInstance(true);
System.out.println("----");
getInstance(false);
}
}

1、新建数组会导致LazyHolder的加载吗?会导致它的初始化吗?

答:会加载元素类LazyHolder,不会初始化元素类。

2、新建数组会导致LazyHolder的来链接吗?

答:不会链接元素类LazyHolder;在getinstance(false)时才真正链接和初始化。

极客时间 深入拆解java虚拟机 一至三讲学习总结的更多相关文章

  1. java爬虫系列第四讲-采集"极客时间"专栏文章、视频专辑

    1.概述 极客时间(https://time.geekbang.org/),想必大家都知道的,上面有很多值得大家学习的课程,如下图: 本文主要内容 使用webmagic采集极客时间中某个专栏课程生成h ...

  2. "做中学"之“极客时间”课程学习指导

    目录 "做中学"之"极客时间"课程学习指导 所有课程都可以选的课程 Java程序设计 移动平台开发 网络攻防实践 信息安全系统设计基础 信息安全专业导论 极客时 ...

  3. 【视频合集】极客时间 react实战进阶45讲 【更新中】

    https://up2.v.sharedaka.com/video/ochvq0AVfpa71A24bmugS5EewhFM1553702519936.mp4 01 React出现的历史背景及特性介绍 ...

  4. 如何将极客时间课程制作成kindle电子书

    订阅了几个极客时间的专栏,一直没有时间去看. 最近,想着如果把内容制作成电子书,利用上下班时间学习一下,岂不是很方便? 在网上搜到一个很好用的开源软件,几分钟就可以把极客时间的专栏做成电子书,简直太棒 ...

  5. 极客时间_Vue开发实战_汇总贴

    视频地址: https://time.geekbang.org/course/intro/163 https://github.com/tangjinzhou/geektime-vue-1 电脑dem ...

  6. 左耳朵耗子:我为什么要在极客时间 App 开设独家专栏?

    参考链接:https://www.infoq.cn/article/2018/01/why-geektime 不少朋友都知道我在极客时间App 上开了一个收费专栏<左耳听风>,这个专栏会开 ...

  7. 极客时间 Mysql实战45讲 07讲行锁功过:怎么减少行锁对性能的影响笔记 极客时间

    极客时间 Mysql实战45讲 07讲行锁功过:怎么减少行锁对性能的影响笔记 极客时间极客时间 Mysql实战45讲 07讲行锁功过:怎么减少行锁对性能的影响笔记 极客时间 笔记体会: 方案一,事务相 ...

  8. Mysql实战45讲 06讲全局锁和表锁:给表加个字段怎么有这么多阻碍 极客时间 读书笔记

    Mysql实战45讲 极客时间 读书笔记 Mysql实战45讲 极客时间 读书笔记 笔记体会: 根据加锁范围:MySQL里面的锁可以分为:全局锁.表级锁.行级锁 一.全局锁:对整个数据库实例加锁.My ...

  9. Mysql实战45讲 05讲深入浅出索引(下)极客时间 读书笔记

    极客时间 Mysql实战45讲 04讲深入浅出索引(下)极客时间 笔记体会: 回表:回到主键索引树搜索的过程,称为回表覆盖索引:某索引已经覆盖了查询需求,称为覆盖索引,例如:select ID fro ...

随机推荐

  1. spring boot 2.0 neo4j 使用

    参考文档 官方文档 http://spring.io/projects/spring-data-neo4j#learn https://docs.spring.io/spring-data/neo4j ...

  2. git 切换远程仓库,以及碰到的一个问题。

    git 切换远程仓库出现如下问题: $ git checkout -b localdev origin/dev fatal: Cannot update paths and switch to bra ...

  3. 局域网安全-生成树攻击-ARP攻击-MAC攻击-VTP攻击-动态VLAN的攻击

    一.MAC layer attacks 1.CAM表的OVERLOAD 第三方设备不断发送变化的MAC地址,填满CAM表,对于后来合法的MAC地址不能学习到从而泛洪,这时攻击者将学习到合法者的数据包. ...

  4. C++ log4cplus 类库的封装

    对 log4cplus 库的封装,修改自网路 LogUtils.h /* * LogUtils.h * * Created on: 2018年8月9日 * Author: oftenlin */ #i ...

  5. css Margin-top塌陷,解决方法

    在两个盒子嵌套时,内部的盒子设置的margin-top会加到外边的盒子上,导致内部的盒子margin-top设置失败,解决方法如下: (1)外部盒子设置一个边框 (2)外部盒子设置overflow:h ...

  6. hadoop2集群环境搭建

    在查询了很多资料以后,发现国内外没有一篇关于hadoop2集群环境搭建的详细步骤的文章. 所以,我想把我知道的分享给大家,方便大家交流. 以下是本文的大纲: 1. 在windows7 下面安装虚拟机2 ...

  7. python进阶篇

    python进阶篇 import 导入模块 sys.path:获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到. ​ import sys ...

  8. angular.identity()

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. BOM 浏览器对象模型_不超过 4 KB 的 document.cookie 对象

    注意: 客户端储存应该使用 Web storage API 和 IndexedDB,不推荐使用 Cookie document.cookie 对象 是服务器保存在浏览器的一小段文本信息 用于读写当前网 ...

  10. JavaScript学习day2 (基本语法上)

    知识点 JavaScript 的变量 数据类型 运算符 JavaScript 的动态类型 变量:(变量的命名规则和其他语言类似) 由数字,字母,下划线组成,区分大小写 以字母开头 变量名不能有空格 不 ...