首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java虚拟机知识点简要梳理

java虚拟机知识点简要梳理

作者头像
lyb-geek
发布2018-09-27 09:52:53
5520
发布2018-09-27 09:52:53
举报

首先来看一个java虚拟机的思维导图,下面每个知识点都可以进行展开,本篇只做简要梳理

上图是从类的整个生命来梳理的,包括类的加载、验证、准备、解析、初始化、使用、卸载,将一一做简要介绍

一、加载

1.加载过程

a.通过类的全限定名获取类的二进制字节流,其中二进制字节流不一定是java语言编译的,只要是最终形成符合java字节流格式即可,比如jruby、jython、groovy等都可以编译成java的二进制字节流

b.将字节流转化为方法区运行时数据结构

c.在内存中生成一个代表该类的java.lang.Class对象,作为该类的访问入口

2.class文件结构

class文件格式采取类似于C语言结构体的伪结构来存储,只有两种数据类型,一个无符号类型,另一个是表,表由多个无符号类型和其他表结构组成的复合数据类型,整个class其实就是一张表。

ClassFile {
u4 magic;//魔数(0xCAFEBABE)
u2 minor_version;//次版本号
u2 major_version;//主版本号
u2 constant_pool_count;//常量池容量计数值
cp_info constant_pool[constant_pool_count-1];//常量池
u2 access_flags;//访问标志
u2 this_class;//类索引
u2 super_class;//父类索引
u2 interfaces_count;//接口计数器
u2 interfaces[interfaces_count];//接口索引集合
u2 fields_count;//字段计数器
field_info fields[fields_count];//字段表
u2 methods_count;//方法计数器
method_info methods[methods_count];//方法表
u2 attributes_count;//属性表计数器
attribute_info attributes[attributes_count];//属性表集合
}

3.双亲委派模型

类加载采用的是双亲委派模型,用下图来说明

类加载器有四种,启动类加载器,是C/C++实现,无法在java代码中调用,扩展类加载器、应用类加载器和自定义类加载器,双亲委派模型指的是当前类加载器加载某个类的时候,如果没有找到,首先调用的父类加载器,如果父类加载器没有找到这个类,则再往上的父类查找,一直到顶层的启动类加载器,如果还是找不到,则启动类加载器尝试加载这个类,如果没有加载成功,则返回空给子加载器,子加载器如果也没有加载到,则继续往下的类加载器走,一直到当前类加载器。过程如下:

(1).如果一个类加载器收到了类加载请求,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器去完成。

(2).每一层的类加载器都把类加载请求委派给父类加载器,直到所有的类加载请求都应该传递给顶层的启动类加载器。

(3).如果顶层的启动类加载器无法完成加载请求,子类加载器尝试去加载,如果连最初发起类加载请求的类加载器也无法完成加载请求时,将会抛出ClassNotFoundException,而不再调用其子类加载器去进行类加载。

双亲委派模式的类加载机制的优点是java类它的类加载器一起具备了一种带优先级的层次关系,越是基础的类,越是被上层的类加载器进行加载,保证了java程序的稳定运行。

二、验证

1.文件格式验证

魔法数字、版本号、不支持的常量类型,索引值指向错误等

2.元数据验证

字节码描述信息语义分析。是否有父类、是否继承了不该继承的类、未实现抽象类或接口的全部方法等

3.字节码验证

程序语义是否合法、符合逻辑。

4.符号引用验证

该过程是在解析阶段发生的,符号引用转换成直接引用的时候。能否找到对应的类、符号引用中的类的方法、字段、类是否可被当前类访问等

三、准备

类变量初始化,分配内存并设置初始值("0"值)

四、解析

符号引用转化为直接引用

五、初始化

按照代码中定义的操作进行赋值操作和静态语句块的执行

六、使用

这一块的东西应该是最多的

1.运行时数据区

线程私有:

a.程序计数器

下一条需要执行的字节码命令

b.java虚拟机栈

(1)为每个方法的创建一个栈帧,方法的开始和结束对应栈帧的进栈和出栈

(2)栈帧包含局部变量表,操作数,动态链接,返回地址等

c.本地方法栈

和java虚拟机栈相似,只是执行的是本地方法

线程共享:

d.堆

存放对象实例和数组

e.方法区

保存了类信息,常量,静态变量,即时编译后的代码等数据

2.垃圾收集机制

上面的线程私有的不需要考虑回收问题,因为随着线程的结束或方法的结束,自然会被回收掉,而方法区的中数据保留的是类信息、常量、静态变量等,这一部分的数据很少需要被回收,因此重点在于堆里面的数据,而且这一块的数据是最多的。

(1)垃圾回收的原理

从一系列GC Roots对象出发,向下搜索,所走过的路径被称为引用链,当一个对象到GC Roots没有任何一条引用链时,该对象是不可用的,应该被回收掉。(可达性分析)

能够作为GC Roots基本上收集器很少或不会作用到的地方,比如方法区的静态变量或常量引用的对象,虚拟机栈或本地方法栈的引用的对象。

(2)垃圾收集机制

新生代和老年代采用的是不同的垃圾收集机制

a.新生代特点是朝生夕死。采用的复制算法,即可用的内存平均分为2块,每次只用一块,gc时,将使用的那一块存活的对象复制到另一块中,然后原有块空间一次清理掉。

b.年老代特点是生存周期比较长。采用的是标记整理算法或标记清除算法,标记清除算法是把要回收的对象进行标记,然后再把它清理掉,而标记压缩算法则是把所有存活的对象向一端移动,然后清理掉边界以外的空间。

(3)常用垃圾收集器和优缺点

垃圾收集器比较多,只列举典型的

Serial收集器:单线程收集器,简单高效,cpu利用率高,等待时间久

Parellel Scavenge收集器:多线程,停顿时间和吞吐量之间要平衡

CMS收集器:响应优先,停顿时间短

G1收集器:并行与并发、分代收集、空间整合、可预测停顿

3.java内存模型

(1)三大原则

原子性:基本的操作,比如read、load、assign、write、save等原子性的

有序性:单线程的执行结果是确定的,不会改变,多线程无此要求

先行原则:如果一个操作先行于另一个操作可见,必然先行于另一个操作

(2)volatile

用volatile修饰的变量,读取操作要从主内存直接读取最新的值,赋值操作完成之后要刷到主内存当中,该原理是通过插入内存屏障指令,由CPU原生就支持

(3)synchronized

和volatile所不同的是,代码块整个从主内存读取,然后解锁之前刷新到主内存,实现原理则是监控锁

(4)锁优化

a.自旋锁

短时间做空操作,没有获取锁则再阻塞

b.锁消除

如果一段代码确定不会被多个线程同时访问,则去掉锁

c.锁粗化

如果加锁和解锁频繁或者干脆在循环里,则考虑把锁粗化

d.轻量锁

通过CAS操作更新Mark Word上的锁状态,如果没有更新成功,则检查是否是当前线程获取锁,如果还不是,则阻塞

e.偏向锁

通过CAS操作获取了锁,如果下次还是同一个线程,则不再执行锁同步,直接执行代码块,如果不是,偏向锁失败,则阻塞

4.JIT技术

当某个方法通过计数的方式,当次数超过一定阈值时,会将其编译为本地码(时间会比较长),当下次再调用该方法时,直接调用本地码。

七、卸载

虽然说有人把方法区称作为永久区,但实际上还是有可能被回收掉的,当某个类确定不再被使用时,可以从方法区中卸载

参考文档:

1.《深入理解java虚拟机》

2.class类文件解析(http://blog.csdn.net/kobejayandy/article/details/39620833)

3.双亲委派模型(http://blog.csdn.net/p10010/article/details/50448491)

4. java内存模型(http://blog.csdn.net/newhope1106/article/details/55803225)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档