JVM内核-原理、诊断与优化学习笔记(一):初识JVM

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指令代码(如上)。

转载于:https://www.cnblogs.com/LeesinDong/p/10835383.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值