您的位置:首页 > 文旅 > 旅游 > JVM详解

JVM详解

2024/12/23 9:54:12 来源:https://blog.csdn.net/m0_64308748/article/details/140208249  浏览:    关键词:JVM详解

目录

一、介绍

1.定义

2.组成划分

二、类加载系统

1.类的加载过程

2.类加载器

三、双亲委派机制

过程

双亲委派模型的优点

四、运行时数据区

五、对象的创建流程

六、垃圾回收机制

1.定义

1.1 引用计数法

1.2 可达性分析算法:GC Roots根

2.垃圾回收算法

2.1 标记-清除算法

2.2 复制算法

2.3 标记-整理算法

2.4 分代收集算法

3.垃圾回收器

3.1 Serial收集器

3.2 Parallel收集器

3.3 ParNew收集器

3.4 CMS收集器

3.5 三色标记算法

3.6 垃圾收集器组合方案


一、介绍

1.定义

JVM是什么?

Java Virtual Machine(JVM)即Java虚拟机,是Java程序实现跨平台的一个重要的工具(部件)。

2.组成划分

jvm主要由三个部分组成:类加载系统、运行时数据区、执行引擎。

类加载系统:负责完成类的加载

运行时数据区:在运行Java程序的时候会产生的各种数据会保存在运行时数据区

执行引擎:执行具体的指令(代码)

二、类加载系统

1.类的加载过程

类加载的基本流程

类加载就是java代码会被编辑成.class文件,java程序想要运行起来,就需要让jvm读取到这些.class文件,并且把里面的内容,构造成类对象,保存到内存的方法区中。

A.加载:找到.class文件,打开文件,读取文件内容

B.验证:.class文件是一个二进制的格式(每个字节,都是有特殊含义的)

就需要验证你当前读到的这个格式是否符合要求

C.准备:给类对象分配内存空间(最终的目标,是要构造出类对象)

这里只是分配内存空间,还没有初始化,此时这个空间上的内存的数值,就是全0的

D.解析:针对类对象中包含的字符串常量进行处理,进行一些初始化操作。

java代码中用到的字符串常量,在编译之后,也会进入到.class文件中

E.初始化:针对类对象进行初始化

2.类加载器

三、双亲委派机制

JVM中,内置了,三个类加载器

1.BootStrap ClassLoader      爷

2.Extension ClassLoader       父

3.Application ClassLoader      子

程序员也可以手动创建出新的类加载器

过程

1.给定一个全限定类名,形如java.lang.String

2.从Application ClassLoader作为入口,开始执行查找的逻辑

3.Application ClassLoader,不会立即去扫描自己负责的目录(负责的是搜索项目当前目录和第三方库对应目录),而是把查找的任务,交给它的父亲(Extension ClassLoader )

4.Extension ClassLoader 也不会立即扫描自己负责的目录(负责的是JDK中一些扩展的库,对应的目录),而是把查找的任务,交给它的父亲(.BootStrap ClassLoader )

5..BootStrap ClassLoader 也不想立即扫描自己负责的目录(负责的是标准库的目录)

也想把任务交给自己的父亲,但是它没有父亲,只能亲自负责扫描,标准库的目录

6.没有扫描到,就回到Extension ClassLoader

Extension ClassLoader就会负责扫描负责的扩展库的目录,如果找到,就执行后续的类加载操作,此时查找过程结束

如果没找到,就还是把任务来交给孩子来执行

7.没有扫描到,就回到Application ClassLoader

Application ClassLoader就会负责扫描当前项目和第三方库的目录,如果找到,就会继续后续的类加载操作

如果没找到,就会抛出异常ClassNotFoundExeception

之所以高这一套流程,主要目的,即使为了确保,标准库的类,被加载的有优先级最高,其次是扩展库,其次是自己写的类和第三方库

双亲委派模型的优点

a. 避免重复加载类:比如A类和B类都有⼀个⽗类C类,那么当A启动时就会将C类加载起来,那

么在B类进行加载时就不需要在重复加载C类了。

b. 安全性:使用双亲委派模型也可以保证了Java的核心API不被篡改,如果没有使⽤双亲委派模

型,而是每个类加载器加载自己的话就会出现⼀些问题,比如我们编写⼀个称为java.lang.Object

类的话,那么程序运行的时候,系统就会出现多个不同的Object类,⽽有些Object类又是用户自己提供的因此安全性就不能得到保证了。

四、运行时数据区

堆空间(线程共享):存放new出来的对象

元空间(线程共享):存放类元信息、类的模板、常量池、静态部分

线程栈(线程独享):方法的栈帧

本地方法栈(线程独享):本地方法产生的数据

程序计数器(线程独享):配合执行引擎来执行指令

五、对象的创建流程

类加载校验:校验该类是否已被加载。主要是检查常量池中是否存在该类的类元信息。如果没有,则需要加载。

Student student = new Student();    //这就是一个类加载

分配内存:为对象分配内存。

具体的分配策略:

Bump the Pointer(指针碰撞):如果内存空间的分配是绝对规整的,则JVM记录当前剩余内存的指针,在已用内存分配。

Free List(空闲列表):如果内存空间的分配不规整,则JVM会维护一个可用内存空间的列表用于分配 。

对象并发分配存在的问题:

Compare And Swap(CAS):自旋分配,如果并发分配失败则重试分配之后的地址。

Thread Local Allocation Buffer(TLAB):本地线程分配缓冲,JVM被每个线程分配一块空间,每个线程在自己的空间中创建对象

设置初值:根据数据类型,为对象空间赋初始化值。

设置对象头:为对象设置对象头信息,对象头信息包含以下内容:类元信息、对象哈希码、对象年龄、锁状态标志等。

不开启指针压缩String类型8字节,开启指针压缩后String类型4字节

对于一个类的main方法:

执行init方法:为对象中的属性复制和执行构造方法。

六、垃圾回收机制

1.定义

什么是垃圾?

在堆空间和元空间中,GC这条守护线程会对这些空间开展垃圾回收工作,GC通过两种算法来判断这些空间中的对象是否是垃圾:

1.1 引用计数法

对象被引用,则计数器+1,如果计数器是0,那么对象将被判定为是垃圾,于是被回收。但是这种算法没有办法解决循环依赖的对象。

1.2 可达性分析算法:GC Roots根

gc roots根节点:在对象的引用中,会有这么几种对象的变量:来自于线程栈中的局部变量表中的变量、静态变量、本地方法栈中的变量,这些变量都被称为gc roots根节点。

判断依据:gc在扫描堆空间中的某个节点时,向上遍历,看看能不能遍历到gc roots根节点,如果不能,那么意味着这个对象是垃圾。

对象中的finalize方法:

Object类中有一个finalize方法,也就是说任何对象都有finalize方法。这个方法是对象被回收之前的最后一根救命稻草。

1.GC在垃圾对象回收之前,先标记垃圾对象,被标记的对象的finalize方法将被调用。

2.调用finalize方法如果被对象引用,那么第二次标记该对象,被标记的对象将移除即将被回收的集合,继续存活。

3.调用finalize方法如果对象没有被吸引,那么将会被回收

注意:finalize方法只会被调用一次

对象的逃逸分析:

对象的建立可能不全是在堆上,也可能在栈上。

2.垃圾回收算法

2.1 标记-清除算法

2.2 复制算法

2.3 标记-整理算法

2.4 分代收集算法

老年代满后,往里面再存储,会报错OVM

对象进入老年代条件:

年龄到达15岁;大对象直接进入老年代(可以通过设置参数,来判断哪些是大对象);根据对象动态年龄判断,如果S区中的对象总和超过了S区中的50%,那么下一次做复制的时候,把年龄大于等于这次最大年龄的对象都一次性全部放入老年代。

3.垃圾回收器

3.1 Serial收集器

单线程执行垃圾收集,收集过程中会有较长的STW,在GC时工作线程不能工作。虽然STW较长,但简单、直接。

新生代采用复制算法,老年代采用标记-整理算法。

3.2 Parallel收集器

使用多线程进行GC,会充分利用cpu但是依然会有stw这是jdk8默认使用的新生代和老年代的垃圾收集器。充分利用CPU资源,吞吐量高。

新生代采用复制算法,老年代采用标记-整理算法。

3.3 ParNew收集器

工作原理和Parallel收集器,都是使用多线程GC,但是区别在于ParNew收集器可以和CMS收集器配合工作。

主流方案为:ParNew收集器负责收集新生代,CMS负责收集老年代。

3.4 CMS收集器

目标:尽量减少stw的时间,提升用户体验。真正做到gc线程和用户线程几乎同时工作。CMS采用标记-清除算法。

出现stw的是初始标记和重新标记两部分,并发清理是最浪费时间的

重新标记是希望更准确的,不能出现并发,所以会有stw

3.5 三色标记算法

在并发标记阶段,对象的状态可能发生改变,GC在进行可达性分析算法分析对象时,用三色来标识对象的状态

黑色:这个对象及其所有引用都已被GC Roots遍历,黑色的对象不会被回收

灰色:这个对象被GC Roots遍历过但其部分的引用没有被GC Roots遍历,在重新标记时重新遍历灰色对象

白色:这个对象没有被GC Roots遍历过,在重新标记时该对象如果是白色的话,那么将会被回收

3.6 垃圾收集器组合方案

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com