JVM(Java Virtual Machine)

目录

一、概念

二、JVM执行流程

1.堆

 2.方法区

3.Java虚拟栈

4.本地方法栈

5.程序计数器

6.异常情况

三、JVM类加载

 1.加载

2.验证

3.准备

4.解析

5.初始化

6.类加载机制

四、垃圾回收

1.不同变量创建和销毁

2.判断是否垃圾

3.老年代和新生代

4.垃圾回收算法

5.垃圾回收线程

6.垃圾回收器


一、概念

Java虚拟机,模拟CPU执行指令的程序

tips:JDK、JRE、JVM的区别

JDK包含JRE,JRE包含JVM。JDK下的文件有jre文件,有bin文件;在bin文件中有java.exe(在jre文件下也有bin,bin下也有java.exe),通过java.exe程序来运行xxx.class字节码,启动的时候会创建一个JVM。

二、JVM执行流程

class文件加载到Java进程的内存中(运行时数据区)

线程共享的:堆、方法区(gc只回收这两个区的)

线程私有的:虚拟机栈、本地方法栈、程序计数器

1.堆

使用new创建的对象(数组等),jdk1.8中常量池也是在堆中,随着程序运行创建,退出而销毁,堆中数据只要还在使用就不会销毁。

tips:对象是等号右边的;变量是等号左边的

 在gc(垃圾回收)中,堆会分为两个区域:新生代、老年代。新生代中放新建的对象,经过一定gc次数后会放入老年代

 2.方法区

存放类(把类加载到方法区,保存类的代码数据;在堆里边生成一个Class<类名>的类对象)、常量、静态变量

在gc时,方法区也叫永久代(jdk1.7)(还属于Java进程内存),元空间(jdk1.8)(不属于Java内存是在系统/本地内存)

3.Java虚拟栈

方法运行结束,栈帧被销毁,栈帧保存的数据也被销毁

(1)生命周期与线程相同

(2)线程(main)执行某个方法,就创建该方法的栈帧(入栈),方法返回就出栈

(3)虚拟机栈包含:

a.局部变量表(表中含有变量(=左边的)、基础数据类型的值(如果是基础数据类型,=右边的也在虚拟机栈))

b.操作栈:每个方法生成的一个先进后出的操作栈

c.动态链接:指向运行时常量池的方法引用

利用intern把数据放到运行时常量池

StringBuilder s = new StringBuilder();
s.append("a");
s.toString().intern();

d.方法返回地址:pc寄存器的地址(指向下一个指令的地址)

4.本地方法栈

调用除Java外的语言的函数就是使用本地方法栈

5.程序计数器

用于标识程序行号

6.异常情况

(1)内存溢出VS内存泄漏

OOM(内存溢出):存放的数据大小超出该区域的内存大小(除了程序计数器,其他都有可能发生OOM),结果恶劣,要避免

内存泄漏:线程生命周期太长,始终引用一些不使用的数据(gc无法回收),可用空间减少,最后可能导致OOM 

解决内存泄漏:重启程序、修改bug

(2)OOM  VS StackOverFlow

StackOverFlow:某个线程调用方法,会创建该方法栈帧入栈,如果栈中的栈帧数量超过jvm规定,会报该异常

eg:递归返回逻辑不正确

public void static main(String args[]){

       print();
}
public void print(){
 
       print();
}

三、JVM类加载

 1.加载

(不是类加载)

加载class字节码到Java进程的内存中,在堆中创建类对象

2.验证

验证字节码是否符合JVM的规范

3.准备

为静态变量分配内存和初始值

eg:(1)static常量:赋值为初始值

public static final Integer x=123;

(2)static变量:赋值为缺省值

public static Integer x=123;#变量赋值为Integer的缺省值null
public static int x=123;#变量赋值为int的缺省值0

4.解析

将常量池内的符号引用替换为直接引用的过程
public static int x=123
符号引用:进程未运行,无法表示x指向123,符号引用用来表示这个指向关系
直接引用:进程运行,x指向123(内存地址)

5.初始化

(不是对象的初始化,是类对象的初始化:执行静态变量(真正赋值)、静态代码块等)

6.类加载机制

(1)双亲委派模型(jdk类加载的默认机制)

一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父
类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最 终都应该传送到最顶层的启 动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类) 时,子加载器才会尝试自己去完成加载。
类加载器(从上到下):
BootStrap ClassLoader 启动类加载器
ExtClassLoader             扩展类加载器
AppClassLoader            系统/应用类加载器             
自定义类加载器
上下关系是逻辑上的关系不是extends;前三种类加载器,加载jre目录下,不同的jar包

优点:安全

确保优先采取以上前三种类加载器加载类,如果是自定义类加载器,若遵循双亲委派模型,则不会加载到自定义的java.lang.Object,而是jre中的(安全);若不遵循,则加载到自定义的Object(不安全);但是jdk中,自定义类加载器进行了安全校验:加载类,如果类的全限定名(包名+类名)以java./javax. 开头的包就报错。

缺点:扩展性/灵活性不好

某些场景下,无法事先知道需要加载的类名

(2)破坏双亲委派模型:针对双亲的缺点

SPI机制

四、垃圾回收(区域空间不足,触发该区域的gc)

堆、方法区需要垃圾回收。但是对于方法区很少回收,主要回收堆。

1.不同变量创建和销毁

public class A{
       private Preson x= new Person();#x是成员变量,创建类A的对象时才创建,A的对象销毁时销毁
       public static Person y= new Person();#y是静态变量,类加载时创建,类销毁时销毁
       public static void xxx(){
              Person z= new Person(); #z局部变量,执行到这个代码时创建,出了作用范围销毁

2.判断是否垃圾

(1)引用计数算法

一个对象被引用一次计数器+1,如果为0则是垃圾可回收

缺点:无法解决循环引用问题(未被JVM引用)

(2)可达性分析

通过一系列称为 "GC Roots" 的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为" 引用链 " ,当一个对象到 GC Roots 没有任何的引用链相连时 ( GC Roots 到这个对象不可达 时,证明此对象是不可用的(垃圾)

3.老年代和新生代

老年代:(1)大对象:占据的空间超过jvm规定阈值

               (2)新生代对象存活超过15次

               (3)新生代gc时分配担保失败的对象:新生代90%空间存活对象,放不下的进入老年代

4.垃圾回收算法

(1)标记清除算法(老年代回收算法)

a.标记要回收的对象 b.统一回收

缺点:效率不高、产生大量内存算法

(2)复制算法(新生代回收算法)

将内存某个区域划分成两个大小相同的空间,每次只使用其中一个,回收的时候把存活的对象复制到另一个不用的空间,清除之前的整个空间

适用于大多数对象,朝生夕死,比如局部变量,方法执行完,对象是垃圾

缺点:空间利用率不高

JVM中,EdenSurvivor的大小比例是8 : 1,每次新生代可用内存空间为整个新生代容量的90%,而剩下的10%用来存放回收后存活的对象。 每次使用E区和一个S区

1. 当Eden区满的时候,会触发第一次Minor gc,把还活着的对象拷贝到Survivor From区;当
Eden区再次触发Minor gc的时候,会扫描Eden区和From区域,对两个区域进行垃圾回收,经过
这次回收后还存活的对象,则直接复制到To区域,并将Eden和From区域清空。
2. 当后续Eden又发生Minor gc的时候,会对Eden和To区域进行垃圾回收,存活的对象复制到
From区域,并将Eden和To区域清空。
3. 部分对象会在From和To区域中复制来复制去,如此交换15次(默认值),最终如果还是存活,就存入到老年代

(3)标记整理算法(老年代回收)

a.标记 b.整理:把存活对象往一端移动,清理掉端外的空间

(4)分代算法

新生代采用复制算法,老年代采取标记清除/标记整理

5.垃圾回收线程(守护线程)

一个进程中存在非守护线程,进程就不会结束

垃圾回收线程可以并行执行,但是用户线程有可能并行执行、暂停(SWT)

吞吐量:cpu执行用户代码时间/cpu执行整个进程的时间

吞吐量越高,程序性能越好

6.垃圾回收器

 (1)Serial收集器:新生代收集器(复制算法)

单线程(单个垃圾回收线程),大多数电脑支持多线程,所以这个收集器效率不高,不常使用

(2)ParNew:新生代收集器(复制算法)

多线程搭配CMS(老年代收集器)

(3)Parallel Scanvenge:新生代收集器(复制算法)

吞吐量优先(适用于性能优先的程序),搭配Parallel Old

(4)Serial Old:老年代收集器(标记整理算法)

单线程

(5)Parallel Old:老年代收集器(标记整理算法)

吞吐量优先

(6)CMS收集器(重点)

老年代收集器,并发GC,标记清除算法,用户体验优先(整体是并发,即垃圾回收线程和用户线程同时进行,有局部的stw(少许时间暂停用户线程))

搭配新生代的ParNew收集器

步骤:a.初始标记:标记GC Roots能直接关联的对象,需要STW

           b.并发标记:进行GC Roots引用链追踪的过程(搜索引用路径)

           c.重新标记:修复第二个阶段用户线程同时执行时,产生变动的记录,需要STW

           d.并发清除垃圾

缺陷:a.CPU敏感,吞吐率低,CPU效率低

           b.无法处理浮动垃圾(第四个阶段用户线程并发执行产生的垃圾在此次GC无法回收)

           c.产生大量空间碎片

(7)G1收集器:唯一的全区域垃圾回收器(重点)

步骤:

新生代回收:回收多个E区+多个S区,复制存活对象到空的region区(动态指定为S区)

老年代回收:a.初始标记:类似CMS的初始标记,但是可以和新生代gc同时执行

                      b.并发标记:类似CMS的并发标记,多了优先回收,可以直接回收存活率低/无存活率的region

                      c.最终标记:类似CMS

                      d.筛选回收:筛选存活率低的region回收

理解垃圾回收:在垃圾回收线程中,使用垃圾回收器(垃圾车师傅),先找到垃圾(可达性分析算法),再回收垃圾(采取什么垃圾回收算法)

JVMJava Virtual MachineJava虚拟机)的缩写,它是一种用于计算设备的规范,通过在实际的计算机上仿真模拟各种计算机功能来实现。JVM包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。它的主要任务是运行Java程序,使得Java程序可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。每个Java程序启动时都会产生一个JVM实例,当程序运行结束时,该实例也会消失。JVM是基于堆栈的虚拟机,为每个新创建的线程都分配一个堆栈,通过对堆栈的操作来完成Java程序的运行。JVM对堆栈进行以帧为单位的压栈和出栈操作。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [Java虚拟机Java Virtual Machine(JVM)总结(基于jdk 1.8)](https://blog.youkuaiyun.com/weixin_40923145/article/details/88602359)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Java虚拟机JVM学习笔记](https://blog.youkuaiyun.com/x_panda/article/details/14215819)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值