文章目录

JVM的概念

JVM是Java Virtual Machine的简称。意为Java虚拟机

虚拟机

指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统

有哪些虚拟机

  • VMWare
  • Visual Box
  • JVM

VMWare或者Visual Box都是使用软件模拟物理CPU的指令集

比如它们模拟的cpu、硬盘、内存,等都是现实存在的,能够在现实中找到对应的案例的。

JVM使用软件模拟Java 字节码的指令集

JVM模拟的对象是现实中没有的,现实中没有任何一个计算机能够运行Java字节码,单纯从从软件上做的一个设计,来模拟一个硬件的行为,比如jvm运行的的是java字节码指令集,为了设计上的精简,我们知道正常的cpu中有若干个寄存器,jvm中除了pc寄存器外,其他的寄存器都做了裁剪,因为寄存器的主要功能是加快数据访问的速度,因为在jvm中是纯粹用软件模拟的,速度使用寄存器后并不会有很好的提升,并且引入寄存器后,也为jvm的设计以及实现带来很大的困难,所以把这些功能去掉了。综上,jvm是一个被定制过的现实中不存在的计算机。

JVM发展历史

1996年 SUN JDK 1.0 Classic VM

纯解释运行,使用外挂进行JIT,没有内置的即时编译的模块,一旦开启外挂,解释运行的功能就没有了。

Classic VM生命周期比较长,在1.3 、1.4的时候才被淘汰

1997年 JDK1.1 发布

-AWT、内部类、JDBC、RMI、反射

1998年 JDK1.2 Solaris Exact VM

JIT 解释器混合

Accurate Memory Management 精确内存管理,数据类型敏感

提升的GC性能

JDK1.2开始 称为Java 2

J2SE J2EE J2ME 的出现

加入Swing Collections

Solaris Exact VM生命周期比较短。

2000年 JDK 1.3 Hotspot 作为默认虚拟机发布

加入JavaSound加入了一些声音上的api

2002年 JDK 1.4 Classic VM退出历史舞台

Assert 正则表达式 NIO IPV6 日志API 加密类库

2004年发布 JDK1.5 即 JDK5 、J2SE 5 、Java 5(重要版本)

泛型

注解

装箱

枚举

可变长的参数

Foreach循环

JDK1.6 JDK6

脚本语言支持

JDBC 4.0

Java编译器 API(开放了这个API)

2011年 JDK7发布

延误项目推出到JDK8

G1(全新的gc收集器)

动态语言增强(动态语言的火热)

64位系统中的压缩指针

NIO 2.0

2014年 JDK8发布(重要版本)

Lambda表达式(模拟了函数式编程)

语法增强 Java类型注解

2016年JDK9

模块化

大事件

使用最为广泛的JVM为HotSpot

HotSpot 为Longview Technologies开发 被SUN收购

2006年 Java开源 并建立OpenJDK

HotSpot 成为Sun JDK和OpenJDK中所带的虚拟机

2008 年 Oracle收购BEA

得到JRockit VM

2010年Oracle 收购 Sun

得到Hotspot

Oracle宣布在JDK8时整合JRockit和Hotspot,优势互补

在Hotspot基础上,移植JRockit优秀特性

推测:JRockit在不久的将来会退出历史舞台,但是HotSpot会深受JRockit的影响。

JVM种类

KVM

SUN发布

IOS Android前,广泛用于手机系统

CDC/CLDC HotSpot

手机、电子书、PDA等设备上建立统一的Java编程接口

J2ME的重要组成部分

JRockit

IBM J9 VM

IBM内部

Apache Harmony

兼容于JDK 1.5和JDK 1.6的Java程序运行平台

与Oracle关系恶劣 退出JCP ,Java社区的分裂

OpenJDK出现后,受到挑战 2011年 退役

没有大规模商用经历

对Android的发展有积极作用

BEA

Java语言规范

语法定义

IfThenStatement:

if ( Expression ) Statement

if(true){do sth;}

ArgumentList:

Argument

ArgumentList , Argument

add(a,b,c,d);

词法结构

\u + 4个16进制数字 表示UTF-16

行终结符: CR, or LF, or CR LF.

空白符

空格 tab \t 换页 \f 行终结符

注释

标识符

关键字

//标识符:标识符字符串不能使关键字或者布尔值或者null
Identifier:    IdentifierChars but not a Keyword or BooleanLiteral or NullLiteral
//标识符串:java字符
IdentifierChars:    JavaLetter    IdentifierChars JavaLetterOrDigit
//java字符:任何一个unicode
JavaLetter:    any Unicode character that is a Java letter (see below)
//
JavaLetterOrDigit:    any Unicode character that is a Java letter-or-digit (see below)

小例子

public static void 打印(){
	System.out.println("中文方法哦");
}
public  static void main(String[] args) {
	打印();
}

有意思的是,代码中有中文

数字相关

在jdk1.7中一个比较大的改变是允许有下划线,好处是当数字比较大的时候看的比较清楚一些。

  • Int

    0 2 0372 0xDada_Cafe 1996 0x00_FF__00_FF
  • Long

    0l 0777L 0x100000000L 2_147_483_648L 0xC0B0L
  • Float

    1e1f 2.f .3f 0f 3.14f 6.022137e+23f
  • Double

    1e1 2. .3 0.0 3.14 1e-9d 1e137
  • 操作

    += -= *= /= &= |= ^= %= <<= >>= >>>=

哪些是合法的数字呢?

private int a=0xDada_Cafe;
private float b=0x1.fffffeP+127f;
private float c=1996;
private float d=1996.3;
private int f=9999e2;
private double g=33e2;
private float h=0x1.fffep-12f;
private float i=1.fffep-12f;
private long p=0b1_1_1_0_1;
private long q=0b1_1_1_0_2;

类型和变量

  • 元类型

    byte short int long float char
  • 变量初始值

    boolean false

    char \u0000
  • 泛型
class Value { int val; }

class Test {
    public static void main(String[] args) {
        int i1 = 3;
        int i2 = i1;
        i2 = 4;
        System.out.print("i1==" + i1);
        System.out.println(" but i2==" + i2);
        Value v1 = new Value();
        v1.val = 5;
        Value v2 = v1;
        v2.val = 6;
        System.out.print("v1.val==" + v1.val);
        System.out.println(" and v2.val==" + v2.val);
    }
}

i13 but i24

v1.val6 and v2.val6

i1 i2为不同的变量

v1 v2为引用同一个实例

Java内存模型

类加载链接的过程

public static final abstract的定义

异常

数组的使用

…….

JVM规范

Java语言规范定义了什么是Java语言

Java语言和JVM相对独立

符合JVM规范的就能够在JVM上运行,比如:

  • Groovy

  • Clojure

  • Scala

    JVM主要定义二进制class文件和JVM指令集等

  • Class 文件格式

  • 数字的内部表示和存储

    Byte -128 to 127 (-27 to 27 - 1)

  • returnAddress 数据类型定义

    指向操作码的指针。不对应Java数据类型,不能在运行时修改。Finally实现需要

  • 定义PC

  • 方法区

整数的表达

  • 原码:第一位为符号位(0为正数,1为负数)
  • 反码:符号位不动,原码取反
  • 负数补码:符号位不动,反码加1
  • 正数补码:和原码相同
  • 打印整数的二进制表示
int a=-6;
//因为整数有32位,所以进行32次循环。
for(int i=0;i<32;i++){
//0x80000000表示最高位为1的数字,所以a & 0x80000000只有一位是1,
//第一次i=0,就是把a的第一位取出来,无符号右移(31-i)位。
//依次循环,将每一位打印出来
	int t=(a & 0x80000000>>>i)>>>(31-i);
	System.out.print(t);
}
5
00000101
-6
原码: 10000110
反码: 11111001
补码: 11111010
-1
原码: 10000001
反码: 11111110
补码: 11111111

为什么要用补码?

0是一个比较特殊的数字,既不属于正数,也不属于负数

计算0的表示:

0
正数:00000000
负数:10000000
0
正数:00000000
0
负数:10000000
反码:11111111
补码:00000000

看到这里补码的好处是为了没有歧义的表示零

-6+5
    11111010
+ 00000101
= 11111111
-4+5
    11111100
+ 00000101
= 00000001
-3+5
    11111101
+ 00000101
= 00000010

看到这里,补码还有一个好处就是方便的计算两个数字之和(两个补码之和,符号位直接参与运算,得到的记过就是正确的结果。如果是源码做计算,符号位参与运算得不到正确的结果。),当然减法是一个特殊的加法。

Float的表示与定义

支持 IEEE 754

s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm

s符号位 eeeeeeee 指数:8 mmmmmmmmmmmmmmmmmmmmmmm 尾数:23

e全0 尾数附加位为0 否则尾数附加位为1,所以这里的尾数看似是23位,实质上是24位。

表达式

s*m*2^(e-127)

m指的是后面的23位

例子

-5
1 10000001 01000000000000000000000
-1*2^(129-127)*(2^0+2^-2)

一些特殊的方法

clinit 类的初始化方法

init 实例的初始化方法

JVM指令集

  • 类型转化

    l2i
  • 出栈入栈操作

    因为虚拟机没有寄存器,所以很多的指令都是通过栈的方式来操作的,所以有一系列的指令来定义出栈和入栈的操作。

    aload astore
  • 运算

    iadd(+) isub(-)
  • 流程控制

    ifeq(相等) ifne(不相等)
  • 函数调用

    invokevirtual(调用虚函数) invokeinterface (调用接口) invokespecial invokestatic (调用静态)

JVM需要对Java Library 提供以下支持:

因为这些功能没有办法通过java语言本身支持,所以通过JVM实现。

  • 反射 java.lang.reflect
  • ClassLoader
  • 初始化class和interface
  • 安全相关 java.security
  • 多线程
  • 弱引用

JVM的编译

源码到JVM指令的对应格式

Javap 反编译

JVM反汇编的格式:

<index> <opcode> [ <operand1> [ <operand2>... ]] [<comment>]

索引(偏移量) 操作码(±*/入站出站) 注解

例子

void spin() {
  int i;
  for (i = 0; i < 100; i++) { ;
     // Loop body is empty
   }
 }
0   iconst_0       // Push int constant 0
1   istore_1       // Store into local variable 1 (i=0)
2   goto 8         // First time through don't increment
5   iinc 1 1       // Increment local variable 1 by 1 (i++)
8   iload_1        // Push local variable 1 (i)
9   bipush 100     // Push int constant 100
11  if_icmplt 5    // Compare and loop if less than (i < 100)
14  return         // Return void when done

在JVM中直接执行的是JVM指令代码(如上)。

JVM内核-原理、诊断与优化学习笔记(一):初识JVM的更多相关文章

  1. 深入JVM内核---原理,诊断与优化

    JVM的概念 JAM是Java Virtual Machine的简称.意为Java虚拟机 虚拟机 指通过软件模拟的具有完整硬件系统功能的,运行在一种完整隔离环境中的完整计算机系统 有哪些虚拟机 - V ...

  2. JVM内核-原理、诊断与优化学习笔记(八):JAVA堆分析

    文章目录 内存溢出(OOM)的原因 在JVM中,有哪些内存区间? 堆溢出 永久区 Java栈溢出 直接内存溢出 小问题? MAT使用基础 柱状图显示 支配树 显示线程信息 显示堆总体信息,比如消耗最大 ...

  3. JVM内核-原理、诊断与优化学习笔记(七):性能监控工具

    文章目录 系统性能监控 系统性能监控- linux uptime top vmstat(虚拟内存统计) pidstat 系统性能监控 - windows 任务管理器 Perfmon Process E ...

  4. JVM内核-原理、诊断与优化学习笔记(四):GC算法与种类

    文章目录 GC的概念 GC算法 引用计数法 引用计数法的问题 标记清除 标记压缩 小问题 复制算法 复制算法的最大问题是:空间浪费 整合标记清理思想 -XX:+PrintGCDetails的输出 gc ...

  5. JVM内核-原理、诊断与优化学习笔记(三):常用JVM配置参数

    文章目录 Trace跟踪参数 -verbose:gc (打开gc的跟踪情况) -XX:+printGC(打开gc的log开关,如果在运行的过程中出现了gc,就会打印出相关的信息.) -XX:+Prin ...

  6. JVM内核-原理、诊断与优化学习笔记(二):JVM运行机制

    文章目录 JVM启动流程 PC寄存器 方法区 保存装载的类信息 通常和永久区(Perm)关联在一起 Java堆 Java栈 Java栈 – 局部变量表 ** 包含参数和局部变量 ** Java栈 – ...

  7. JVM内核-原理、诊断与优化学习笔记(六):类装载器

    文章目录 class装载验证流程 class装载验证流程 class装载验证流程 -加载 class装载验证流程 -链接 验证 链接 -> 验证 文件格式的验证 元数据验证(class文件简单语 ...

  8. JVM内核-原理、诊断与优化学习笔记(十一):JVM字节码执行

    文章目录 javap javap 举个

  9. JVM内核-原理、诊断与优化学习笔记(十):Class文件结构

    文章目录 语言无关性 文件结构 魔数 版本 常量池 CONSTANT_Utf8 CONSTANT_Integer CONSTANT_String CONSTANT_NameAndType CONSTA ...

随机推荐

  1. 「题解」:$Six$

    问题 A: Six 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 来写一篇正经的题解. 每一个数对于答案的贡献与数本身无关,只与它包含了哪几个质因数有关. 所以考虑二 ...

  2. WebBug靶场基础篇 — 02

    本篇以第一人称记录这个关卡的第 1-5 关. 由于我记录的过程有点偏向于思考,所以截图截的多 = =!所以文章有点长... 下午一觉醒来,已经 4 点多了,然后开电脑,在虚拟机里,铺了铺靶场,但是毕竟 ...

  3. 项目管理模式:外瀑布内敏捷(有人称为“信封法”)--转自知乎大神:CORNERSTONE

    作者:CORNERSTONE 链接:https://www.zhihu.com/question/265968122/answer/878124580 来源:知乎 著作权归作者所有.商业转载请联系作者 ...

  4. source insight和vim同时使用

    https://blog.csdn.net/wangn222/article/details/72721993 1.Source Insight中,Options->Custom Command ...

  5. 引入scss(@import)和其中易错点

    1.引入文件方式 @import 'url'; ./ :当前目录 ../ :上级目录 src/api/styles: 绝对路径 2.一般在main.js中引用当做全局样式 import 'styles ...

  6. 拾遗:使用 systemd-journald 管理 Docker 容器日志

    在 docker.service 文件中的 ExecStart 字段中,添加(或:docker run --log-driver=journald): --log-driver=journald \ ...

  7. LitJson使用中的一些问题

    http://blog.csdn.net/n5/article/details/45030063

  8. jsonp的实现原理

    jsonp的实现原理 由于浏览器的安全性(同源策略)限制,不允许AJAX访问协议不同或域名不同或端口号不同的数据接口: 可以通过动态创建script标签的方式,把script标签的src属性指向数据接 ...

  9. 基于nginx结合openssl实现https

    [root@localhost ~]#systemctl stop firewalld[root@localhost ~]#setenforce 0[root@localhost ~]#iptable ...

  10. hdu5421 Victor and String 回文树(前后插入)

    题目传送门 题意:对一个字符串支持四种操作,前插入字符,后插入字符,询问本质不同的回文串数量和所有回文串的数量. 思路: 就是在普通回文树的基础上,维护suf(最长回文后缀)的同时再维护一个pre(最 ...