前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java进阶训练营 第一周JVM 预习笔记

Java进阶训练营 第一周JVM 预习笔记

原创
作者头像
编程之心
修改2020-10-14 10:01:53
8801
修改2020-10-14 10:01:53
举报
文章被收录于专栏:编程之禅编程之禅

1.环境准备

JDK、JRE、JVM关系

JDK = JRE(运行环境) + 开发工具

JRE = JVM + 类库

image.png
image.png

开发Java程序交互关系:

用JDK开发JAVA程序,编译成字节码,打包给装有JRE的程序运行。

JRE启动JVM实例,加载、验证、执行Java字节码及依赖库,运行Java程序。

Linux配置Java环境变量

$ cat ~/.bash_profile

代码语言:javascript
复制
# JAVA ENV
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home
export PATH=$PATH:$JAVA_HOME/bin

让环境配置立即生效:

$ source ~/.bash_profile

查看环境变量:

echo $PATH

echo $JAVA_HOME

查找JDK安装在哪个目录?

jps ‐v

whereis javac

ls ‐l /usr/bin/javac

find / ‐name javac

2.量化性能指标

关注硬件:CPU+内存+IO(磁盘+网络)

衡量系统性能3个维度:

延迟:请求响应时间

吞吐量:交易类每秒事务数(TPS),查询类每秒请求数(QPS)

系统容量:硬件配置

性能调优总结:

第一步:收集数据,制定指标

第二步:分析解决瓶颈问题

3.JVM基础知识

1)编程语言分类

机器语言:二进制编码

汇编语言:缩写英文标符号

高级语言:多种编程语言总称

4.字节码技术

4.1.字节码简介

Java字节码由单字节指令组成,最多支持256个操作码,由前缀+操作名称组成。

指令分为:

1、栈操作指令,包括与局部变量操作指令

2、程序流程控制指令

3、对象操作指令,包括方法调用指令

4、算术运算以及类型转换指令

4.2.获取字节码清单

代码语言:javascript
复制
# javac编译
javac demo/jvm0104/HelloByteCode.java
# javap反编译
javap -c demo/java0104/HelloByteCode.class

4.3.解读字节码清单

4.4.查看class文件中的常量池信息

代码语言:javascript
复制
javap -c -verbose demo.jvm0104.HelloByteCode
ACC_PUBLIC: public类
ACC_SUPER: 调用super类
#1 常量编号
= 分隔符
Mathodref这个常量指向的是一个方法

4.5.查看方法信息

方法描述

image.png
image.png

小括号内 入参/形参信息

左方括号 表示数组

L 表示对象

V 这个返回值是void

image.png
image.png

栈深度stack=2;

局部变量表保留多少个槽位locals=2;

方法的参数个数args_size=1

无参构造函数的个数不是0

对于非静态方法,this将被分配到局部变量表的第0号槽位中

4.6.线程栈与字节码执行模型

每个线程有自己独有的线程栈,用于存储栈帧。

每执行一个方法,JVM都会创建栈帧。

栈帧由操作数栈,局部变量数组以及class引用。

image.png
image.png

class引用指向常量池中class

局部变量数组:方法参数,局部变量

操作数栈是一个LIFO结构的栈, 用于压 入和弹出值。

4.7.方法体中的字节码解读

方法体中字节码解读

方法体中字节码前数字是数组索引号

image.png
image.png
image.png
image.png

4.8.对象初始化指令:new,init,clinit

new创建对象,但没调构造函数

invokespecial调特殊方法,这里构造函数

dup复制栈顶值

astore {N}或astore_{N}赋值给局部变量

putfield将值赋值给实例字段

putstatic将值赋值给静态字段

静态初始化方法<clinit>

4.9.栈内存操作指令

image.png
image.png

dup复制栈顶值

pop删除栈顶值

swap交换栈顶值

dup_x1复制粘贴栈顶值

dup_x2复制粘贴栈顶两个值

4.10.局部变量表

javac -g xx.java

javap -c xx.class

astore_1 将引用地址值存储到编号1的局部变量中

iconst_1 将常量值1加载到栈里面

dstore 4 将double值保存到本地变量4号槽位

静态方法,槽位0没有this引用位置。

image.png
image.png

4.11.流程控制指令

if_icmpge: if,integer,compare,great equal

一个值是否大于等于另一个值

iinc 4,1: 4号槽位值加1

goto 18: 跳到循环开始地方

4.12.算术运算指令与类型转换指令

i2d: int to double

inic 不需要将数值load到操作数栈,直接对LocalVariableTable值进行运算

4.13.方法调用指令和参数传递

invokestatic 调用静态方法

invokespecial 调用构造方法,private方法,超类方法

invokevirtual 调用公共,受保护和打包私有方法

invokeinterface 调用接口

4.14.InvokeDynamic

为了实现动态类型语言

把实际翻译策略隐藏在JDK库实现

5.Java类加载机制

5.1.类的生命周期和加载过程

image.png
image.png

一个类在JVM里的生命周期有7个阶段,

分别是加载(Loading)、验证 (Verification)、准备(Preparation)、解析(Resolution)、初始化 (Initialization)、使用(Using)、卸载(Unloading)。

前五个部分(加载,验证,准备,解析,初始化)统称为类加载

1)加载

找class文件,找不到报NoClassDefFound

2)校验

检查 classfile 语义,常量池中的符号,并执行类型检查

加载所有超类和接口,检查类层次结构

3)准备

创建静态字段,初始化

4)解析

解析常量池,主要有以下四种:类或接口的解析、字段解析、类方法解析、接 口方法解析。

5)初始化

初始化的过程包括执行:

类构造器方法

static静态变量赋值语句

static静态代码块

5.2 类加载时机

5.3 类加载器机制

通过一个类的全限定名a.b.c.XXClass来获取描述此类的Class 对象

系统自带的类加载器分为三种:

启动类加载器(BootstrapClassLoader) 加载 Java 的核心类

扩展类加载器(ExtClassLoader) 加载JRE的扩展目录

应用类加载器(AppClassLoader)加载来自Java命令的classpath或者­cp选项、java.class.path系统属性指定的jar包和类路径

image.png
image.png

类加载机制有三个特点:

  1. 双亲委托:当一个自定义类加载器需要加载一个类,比如java.lang.String,它很 懒,不会一上来就直接试图加载它,而是先委托自己的父加载器去加载,父加载 器如果发现自己还有父加载器,会一直往前找,这样只要上级加载器,比如启动 类加载器已经加载了某个类比如java.lang.String,所有的子加载器都不需要自己 加载了。如果几个类加载器都没有加载到指定名称的类,那么会抛出 ClassNotFountException异常。
  2. 负责依赖:如果一个加载器在加载某个类的时候,发现这个类依赖于另外几个类 或接口,也会去尝试加载这些依赖项。
  3. 缓存加载:为了提升加载效率,消除重复加载,一旦某个类被一个类加载器加 载,那么它会缓存这个加载结果,不会重复加载。

怎么看到加载了哪些类,以及加载顺序?

在类的启动命令行参数加上 ‐XX:+TraceClassLoading 或者 ‐verbose 即 可

6.JMM模型

6.1 JVM内存结构

JVM的内存区域分为: 堆内存 和 栈内存 ;

image.png
image.png

栈保存了调用链上正在执行的方法的局部变量。

每个线程都有一份自己的局部变量副本。

image.png
image.png

方法中使用的原生数据类型和对象引用地址在栈上存储;对象、对象成员 与类定义、静态变量在堆上。

虽然各个线程自己使用的局部变量都在自己的栈上,但是大家可以共享堆 上的对象,特别地各个不同线程访问同一个对象实例的基础类型的成员变量,会给每 个线程一个变量的副本。

6.2 栈内存的结构

image.png
image.png

6.3 堆内存的结构

image.png
image.png

堆内存是所有线程共用的内存空间

6.4 CPU指令与乱序执行

CPU的实现都是采用流水线的方式

通过内部调度把这些指令打乱了执行,充分利用流水线资源

6.5 JMM背景

JMM规范明确定义了不同的线程之间,通过哪些方式,在什么时候可以看见其他线程 保存到共享变量中的值;以及在必要时,如何对共享变量的访问进行同步。

6.6 JMM简介

  1. JVM的内存区域分为: 堆内存 和 栈内存 ;
  2. 堆内存的实现可分为两部分: 堆(Heap) 和 非堆(Non‐Heap) ;
  3. 堆主要由GC负责管理,按分代的方式一般分为: 老年代+年轻代;年轻代=新生代 +存活区;
  4. CPU有一个性能提升的利器: 指令重排序 ;
  5. JMM规范对应的是 JSR133, 现在由Java语言规范和JVM规范来维护;
  6. 内存屏障的分类与作用。

6.7 内存屏障简介

JMM引入了内存屏障机制。

内存屏障可分为 读屏障 和 写屏障 ,用于控制可见性。 常见的 内存屏障 包括:

代码语言:javascript
复制
#LoadLoad
#StoreStore
#LoadStore
#StoreLoad

#LoadLoad , 那么屏障前面的Load指令就一定要先执行完,才能执行 屏障后面的Load指令。 比如我要先把a值写到A字段中,然后再将b值写到B字段对应的内存地址。如果 要严格保障这个顺序,那么就可以在这两个Store指令之间加入一个

#StoreStore 屏障。 遇到

#LoadStore 屏障时, CPU自废武功,短暂屏蔽掉指令重排序功能。

#StoreLoad 屏障, 能确保屏障之前执行的所有store操作,都对其他处理器可 见; 在屏障后面执行的load指令, 都能取得到最新的值。换句话说, 有效阻止屏障 之前的store指令,与屏障之后的load指令乱序 、即使是多核心处理器,在执行这 些操作时的顺序也是一致的。

参考资料

极客时间-Java进阶训练营

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.环境准备
  • 2.量化性能指标
  • 3.JVM基础知识
  • 4.字节码技术
    • 4.1.字节码简介
      • 4.2.获取字节码清单
        • 4.3.解读字节码清单
          • 4.4.查看class文件中的常量池信息
            • 4.5.查看方法信息
              • 4.6.线程栈与字节码执行模型
                • 4.7.方法体中的字节码解读
                  • 4.8.对象初始化指令:new,init,clinit
                    • 4.9.栈内存操作指令
                      • 4.10.局部变量表
                        • 4.11.流程控制指令
                          • 4.12.算术运算指令与类型转换指令
                            • 4.13.方法调用指令和参数传递
                              • 4.14.InvokeDynamic
                              • 5.Java类加载机制
                                • 5.1.类的生命周期和加载过程
                                  • 1)加载
                                  • 2)校验
                                  • 3)准备
                                  • 4)解析
                                  • 5)初始化
                                • 5.2 类加载时机
                                  • 5.3 类加载器机制
                                  • 6.JMM模型
                                    • 6.1 JVM内存结构
                                      • 6.2 栈内存的结构
                                        • 6.3 堆内存的结构
                                          • 6.4 CPU指令与乱序执行
                                            • 6.5 JMM背景
                                              • 6.6 JMM简介
                                                • 6.7 内存屏障简介
                                                • 参考资料
                                                领券
                                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档