JVM虚拟机(面试重)

目录

一.JVM

1>.介绍

2>.JVM的内存分配

1.程序计数器

2.栈

3.堆

4.元数据区(java8之前为方法区)

3>.类加载机制

1.加载

2.验证

3.准备

4.解析

5.初始化

6.小总结

4>.jvm垃圾回收机制GC

1.认识GC

2.GC回收的对象

3.第一种寻找方案:引用计数

4.第二种寻找方案:可达性分析算法

5.处理方式

(1).标记清除

(2).复制算法

(3).标记整理法

6.分代回收

7.垃圾回收器



一.JVM

1>.介绍

在之前的学习,知道一个java程序运行的过程:.java程序被javac编译成.class二进制文件,最终在JVM虚拟机解释并运行

JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机

作用:将二进制字节码文件翻译为二进制指令并运行

对于c/c++来说,一次编写多次编译 ,当换个电脑可能代码运行出错,是因为每个电脑的指令与API各有差异,所以要多次调试;对于java、PHP、大蟒蛇来说,代码都是通过虚拟机编译的运行的,只需要一次编写,就可以到处运行

**注:**与软件虚拟机不一样,软件虚拟机指通过软件模拟一个真实的电脑,包括:cpu、显卡等;而这里的JVM只起到翻译并运行的作用

2>.JVM的内存分配

每一次JVM启动时,就会从内存申请一块空间,后续应用程序在运行时,就可以按照JVM内存进行分配

而申请的内存空间:

1.程序计数器

很小一块内存空间里,用于指向下一条要执行的java字节码指令地址的一个数字

2.栈

此栈非数据结构的栈,而是java程序用于维护方法调用关系的栈,结构依然是先进后出,分为两类

(1).虚拟机栈

存储java方法调用关系的栈

递归 也是函数内调用自己,因为有虚拟机栈 的存在,才能定位到自己返回到哪里,而在多线程 中,每一个线程都会有自己的栈与计数器 ,为的就是确保执行顺序与返回正确,而剩下的一个进程存在一份

(2).本地方法栈

专门给一些不是Java代码实现的方法,提供的存储调用关系的栈

比如:jJVM底层是c++实现的,就需要调用一些函数,此时在本地方法栈存储函数的调用关系

3.堆

最大的内存区域 ,用于存储对象普通成员变量

4.元数据区(java8之前为方法区)

JVM将.class文件解析表示出来的类对象static修饰的属性

3>.类加载机制

类加载的过程总共分为5个(详细) / 3个(合并)

1.加载

找到对应的.class文件.并打开文件将二进制数据存纯在内存中

引入概念:

全限定类名:由包名与类名组合在一起;

如:java.util.Scanner:就是一个全限定类名

具体过程如下:

2.验证

根据java官方规定的模版,验证其二进制数据的正确性

可以在该网址下查看: 第 4 章。类文件格式

总的而言,这个过程会将对应的二进制数据套入该模版,若失败,则类有问题直接报错;否则,继续向下类加载

3.准备

给要创建的类对象申请一块空间,并把static修饰的成员值全部为默认值

比如:static String age = "123",在这一步 age = null;

4.解析

针对常量池进行初始化,即把当前.class中的字符串常量(无论静态还是普通属性)放入内存(字符串常量池)中

5.初始化

针对类对象进行初始化,此时开始进行:静态方法/属性-->实例成员方法/属性-->构造方法的初始化流程

6.小总结

听起来有点难搞,画个图再清晰一下最终形成的class对象的面目

对应了我在反射提到的class对象

4>.jvm垃圾回收机制GC

1.认识GC

C 语言需手动通过 malloc 分配、free 释放内存,若未正确释放会导致内存泄漏;而 Java 引入自动垃圾回收机制(GC), 属于后台进程 ,能"周期性"自动识别回收 不再使用的对象内存,大幅减少内存泄漏问题

2.GC回收的对象

每个线程 都会有自己一份栈区程序计数器 ,他们随着线程结束而销毁 ,而在进程中又共享元数据区与堆区, 元数据区存储类对象与静态属性 且全局只中有一份,不需要处理;在堆区有大量的对象存在,有些则创建但没使用,因此GC回收的就是堆区的对象

3.第一种寻找方案:引用计数

简述 :创建的对象在堆区 会有一块计数空间,大小不固定一般为8字节

工作原理 :每有一个引用指向该对象 ,计数器自动 + 1 ,若某个时刻计数器变0,此时GC就会回收该空间

如图:

**优点:处理速度快,**当计数器的值为0,就直接释放内存,无需等待GC周期性检验导致的时耗

缺点一: 堆内存开销严重

堆内存是有限的 ,当堆中开辟了大量的对象,每个对象又额外有8字节的"计算空间",整体的空间开销太大了

缺点二:循环引用

java 复制代码
Test A = new Test();
Test B = new Test();

A.xxx = B;
B.xxx = A;

A = null;
B = null;

后续进行赋值,即:

此时这种情况,想要访问0x002对象,但此时该引用在0x001中,要想找到0x001对象,就必须在0x002对象内访问,.........................开始循环,并且此时这两个对象引用个数不为0无法销毁且无法获得

因为这些问题,JVM并没有采取引用计数方式

4.第二种寻找方案:可达性分析算法

从特定的根对象集合开始向下遍历,遇到不可达时先标记不可达对象,经过确认后才会被回收销毁

听起来很绕,举个例子来阐述根对象:

java 复制代码
// 有以下类
TestA{
   TestB B = new TestB();
   TestC C = new TestC();
   TestD D = new TestD();
} 
TestB{
   TestF F = new TestF();
}
TestC{
   TestG G = new TestG();
}
TestD{
   TestH H = new TestH();
}

具体流程:移动

  1. 从一系列 "根对象"(GC Roots) 开始,这些根对象 包括虚拟机栈中引用的对象常量池引用指向的对象所用引用类型的对象
  2. 从根对象出发,向下遍历所有能直接或间接引用 到的对象,形成 "可达性对象集合"
  3. 堆中所有未被纳入这个可达性集合的对象,被视为 "不可达对象"
  4. 不可达对象并不会立即被销毁,它们需要经历至少两次标记过程,只有真正 "死亡" 的对象才会被垃圾回收器清理

优点:没有引入额外内存,没有循环引用问题

缺点 :可达性分析的遍历非常消耗CPU资源

5.处理方式

垃圾可以通过上述两种方式找到,但具体如何销毁?

(1).标记清除

直接将标记的数据直接清除

发现清除后内存变得不连续的,当后续创建对象时,可能总体上剩余空间足够,但没有连续且合适的空间开辟对象

优点:开发维护低,减少移动对象的CPU 消耗(下面讲到)

缺点:造成内存碎片化

(2).复制算法

堆空间 一分为二,先把对象 放在一侧(左),等进行标记 后,将**"存活"**的对象放在另一侧(右),并整体销毁左侧对象

优点:解决了碎片化空间问题

缺点:

a.空间利用率低(一分为二,只能用一边)

b. 若当前存活的对象多 ,此时赋值就要消耗大量资源

(3).标记整理法

在标记删除的基础标记要删除的对象,将存活的对象向前移动,并将清除边界

类似于数组删除元素

优点: 解决了碎片化空间,增加空间利用率

缺点:移动消耗的资源还是有点大

6.分代回收

Jvm真正的回收机制,集齐了上述的所有优点,根据对象存活不周期的特点,采取不同的方案

每一次GC扫描,对象的"年龄"加一,当一个对象经过多次GC还没回收,后续它大概率还是存活的,这是经验总结

1.新创建 的对象都会放在伊甸区

2.经过一轮扫描后,会把"死亡 "的对象直接标记清除

3.接着存活的对象年龄加一 ,通过复制算法到一个幸存区

4.下一次扫描同时会扫描幸存区 ,"死亡"的对象直接标记清除,存活的年龄加一并放在另一个幸存区

5.随着每一轮扫描,都会将"死亡"的对象清除,存活的年龄加一复制算法到另一个幸存区

6.当"年龄"达到阈值(通常为15) ,就会复制算法到老年区

7.到老年区,扫描频率降低,将少了开销,若发现以"死亡",直接标记清除

注:

(1).若对象内存特别大,为了减少复制开销,也会直接放在老年区

(2).两个幸存区中必然有一个是空闲的(To 区),另一个存放着上一次 GC 后存活的对象(From 区)

7.垃圾回收器

上述的分代回收,只是思想,具体落实在程序上看JVM垃圾回收器

CMS :在不影响业务逻辑情况下,尽可能的多线程标记,减少可达性分析扫描时间

G1 :当内存空间 特别大时.将内存分为更多小块 ,其中有些为伊甸区、幸存区、老年区等,每次只回收其中一部分区域,进行多次回收

ZGC:在不影响业务逻辑下使垃圾回收对业务的影响时间变短(尽量达到0.1ms以内)

OK.到此JVM就告离一段落,若对你有帮助,点个赞吧~~

相关推荐
-睡到自然醒~4 小时前
[go 面试] 并发与数据一致性:事务的保障
数据库·面试·golang
Dolphin_海豚4 小时前
@vue/reactivity
前端·vue.js·面试
怪兽20144 小时前
请谈谈什么是同步屏障?
android·面试
尘世中一位迷途小书童4 小时前
版本管理实战:Changeset 工作流完全指南(含中英文对照)
前端·面试·架构
吃饺子不吃馅4 小时前
【八股汇总,背就完事】这一次再也不怕webpack面试了
前端·面试·webpack
救救孩子把5 小时前
从 JDK 8 到 JDK 23:HotSpot 垃圾回收器全景演进与深度剖析
java·开发语言·jvm·jdk
我命由我123455 小时前
Photoshop - Photoshop 工具栏(14)抓手工具
ui·职场和发展·pdf·求职招聘·职场发展·photoshop·美工
光军oi6 小时前
JAVA全栈JVM篇————初识JVM
java·开发语言·jvm
渣哥6 小时前
当容器里有多个 Bean,@Qualifier 如何精准定位?
javascript·后端·面试