JVM面试知识点整理

news2024/12/31 7:04:50

文章目录

  • (一) JVM组成
    • JVM组成部分和运行流程
    • 从图中可以看出 JVM 的主要组成部分
    • 运行流程:
    • 程序计数器
    • Java堆
    • 虚拟机栈
    • 方法区
    • 堆栈的区别是什么?
  • (二) 类加载器
    • 双亲委派模型
    • 类装载的执行过程
  • (三) 垃圾回收
    • 对象什么时候可以被垃圾回收
      • 哪些可以作为根对象
    • 垃圾回收算法
      • 1) 标记清除
      • 2) 复制
      • 3) 标记整理
    • 分代收集
      • MinorGC、 Mixed GC 、 FullGC的区别是什么
    • JVM 有哪些垃圾回收器
      • 串行垃圾收集器
      • 并行垃圾收集器
      • CMS(并发)垃圾收集器
      • G1垃圾回收器
    • 强引用、软引用、弱引用、虚引用的区别

(一) JVM组成

Java Virtual Machine Java程序的运行环境(java二进制字节码的运行环境)

好处:

  • 一次编写,到处运行
  • 自动内存管理,垃圾回收机制

image.png

JVM组成部分和运行流程

image.png

从图中可以看出 JVM 的主要组成部分

  • ClassLoader(类加载器)
  • Runtime Data Area(运行时数据区,内存分区)
  • Execution Engine(执行引擎)
  • Native Method Library(本地库接口)

运行流程:

(1)类加载器(ClassLoader)把Java代码转换为字节码
(2)运行时数据区(Runtime Data Area)把字节码加载到内存中,而字节码文件只是JVM的一套指令集规范,并不能直接交给底层系统去执行,而是有执行引擎运行
(3)执行引擎(Execution Engine)将字节码翻译为底层系统指令,再交由CPU执行去执行,此时需要调用其他语言的本地库接口(Native Method Library)来实现整个程序的功能。

程序计数器

线程私有的,内部保存的字节码的行号。用于记录正在执行的字节码指令的地址

java虚拟机对于多线程是通过线程轮流切换并且分配线程执行时间。在任何的一个时间点上,一个处理器只会处理执行一个线程,如果当前被执行的这个线程它所分配的执行时间用完了【挂起】。处理器会切换到另外的一个线程上来进行执行。并且这个线程的执行时间用完了,接着处理器就会又来执行被挂起的这个线程。

程序计数器是JVM规范中唯一一个没有规定出现OOM的区域,所以这个空间也
不会进行GC。

Java堆

image.png
线程共享的区域:主要用来保存对象实例,数组等,当堆中没有内存空间可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常。

  • 年轻代被划分为三部分,Eden区和两个大小严格相同的Survivor区,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到老年代区间。
  • 老年代主要保存生命周期长的对象,一般是一些老的对象
  • 元空间保存的类信息、静态变量、常量、编译后的代码为了避免方法区出现OOM,所以在java8中将堆上的方法区【永久代】给移动到了本地内存上,重新开辟了一块空间,叫做元空间。那么现在就可以避免掉OOM的出现了。
    image.png

虚拟机栈

Java Virtual machine Stacks (java 虚拟机栈)

  • 每个线程运行时所需要的内存,称为虚拟机栈,先进后出
  • 每个栈由多个栈帧(frame)组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
  1. 垃圾回收是否涉及栈内存?
    垃圾回收主要指就是堆内存,当栈帧弹栈以后,内存就会释放
  2. 栈内存分配越大越好吗?
    未必,默认的栈内存通常为1024k
    栈帧过大会导致线程数变少,例如,机器总内存为512m,目前能活动的线程数则为512个,如果把栈内存改为2048k,那么能活动的栈帧就会减半
  3. 方法内的局部变量是否线程安全?
    如果方法内局部变量没有逃离方法的作用范围,它是线程安全的
    如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安

栈溢出:
image.png

方法区

  • 方法区(Method Area)是各个线程共享的内存区域
  • 主要存储类的信息、运行时常量池
  • 虚拟机启动的时候创建,关闭虚拟机时释放
  • 如果方法区域中的内存无法满足分配请求,则会抛出OutOfMemoryError:
    image.png

堆栈的区别是什么?

1,栈内存一般会用来存储局部变量和方法调用,但堆内存是用来存储Java对象和数组的的。堆会GC垃圾回收,而栈不会。
2、栈内存是线程私有的,而堆内存是线程共有的。
3,、两者异常错误不同,但如果栈内存或者堆内存不足都会抛出异常。

栈空间不足:java.lang.StackOverFlowError。
堆空间不足:java.lang.OutOfMemoryError。

(二) 类加载器

  • 类加载器:用于装载字节码文件(.class文件)
  • 运行时数据区:用于分配存储空间
  • 执行引擎:执行字节码文件或本地方法
  • 垃圾回收器:用于对JVM中的垃圾内容进行回收

类加载器:
JVM只会运行二进制文件,而类加载器(ClassLoader)的主要作用就是将字节码文件加载到JVM中,从而让Java程序能够启动起来。现有的类加载器基本上都是java.lang.ClassLoader的子类,该类的只要职责就是用于将指定的类找到或生成对应的字节码文件,同时类加载器还会负责加载程序所需要的资源

image.png

类加载器种类
类加载器根据各自加载范围的不同,划分为四种类加载器:

  • 启动类加载器(BootStrap ClassLoader):
    该类并不继承ClassLoader类,其是由C++编写实现。用于加载JAVA_HOME/jre/lib目录下的类库。
  • 扩展类加载器(ExtClassLoader):
    该类是ClassLoader的子类,主要加载JAVA_HOME/jre/lib/ext目录中的类库。
  • 应用类加载器(AppClassLoader):
    该类是ClassLoader的子类,主要用于加载classPath下的类,也就是加载开发者自己编写的Java类。
  • 自定义类加载器:
    开发者自定义类继承ClassLoader,实现自定义类加载规则。

image.png

类加载器的体系并不是“继承”体系,而是委派体系,类加载器首先会到自己的parent中查找类或者资源,如果找不到才会到自己本地查找。类加载器的委托行

双亲委派模型

如果一个类加载器在接到加载类的请求时,它首先不会自己尝试去加载这个类,而是把这个请求任务委托给父类加载器去完成,依次递归,如果父类加载器可以完成类加载任务,就返回成功;只有父类加载器无法完成此加载任务时,才由下一级去加载。
image.png

(1)通过双亲委派机制可以避免某一个类被重复加载,当父类已经加载后则无需重复加载,保证唯一性。
(2)为了安全,保证类库API不会被修改
在工程中新建java.lang包,接着在该包下新建String类,并定义main函数

类装载的执行过程

类从加载到虚拟机中开始,直到卸载为止,它的整个生命周期包括了:加载、验证、准备、解析、初始化、使用和卸载这7个阶段。其中,验证、准备和解析这
image.png

1)加载

  • 通过类的全名,获取类的二进制数据流。
  • 解析类的二进制数据流为方法区内的数据结构(Java类模型)
  • 创建java.lang.Class类的实例,表示该类型。作为方法区这个类的各种数据的访问入口

image.png

2)验证

验证类是否符合JVM规范,安全性检查
(1)文件格式验证:是否符合Class文件的规范
(2)元数据验证
有父类(除了Object这个类之外,其余的类都应该有父类)
这个类是否继承(extends)了被final修饰过的类(被final修饰过的类表示类不能被继承)类中的字段、方法是否与父类产生矛盾。(被final修饰过的方法或字段是不能覆盖的)
(3)字节码验证
主要的目的是通过对数据流和控制流的分析,确定程序语义是合法的、符合逻辑的。
(4)符号引用验证:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量

3) 准备

为类变量分配内存并设置类变量初始值

  • static变量,分配空间在准备阶段完成(设置默认值),赋值在初始化阶段完成
  • static变量是final的基本类型,以及字符串常量,值已确定,赋值在准备阶段完成
  • static变量是final的引用类型,那么赋值也会在初始化阶段完成

4)解析

把类中的符号引用转换为直接引用
比如:方法中调用了其他方法,方法名可以理解为符号引用,而直接引用就是使用指针直接指向方法。
image.png

5) 初始化

对类的静态变量,静态代码块执行初始化操作
如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。

6) 使用

JVM 开始从入口方法开始执行用户的程序代码

  • 调用静态类成员信息(比如:静态字段、静态方法)
  • 使用new关键字为其创建对象实例

(三) 垃圾回收

为了让程序员更专注于代码的实现,而不用过多的考虑内存释放的问题,所以,在Java语言中,有了自动的垃圾回收机制,也就是我们熟悉的GC(GarbageCollection)。
有了垃圾回收机制后,程序员只需要关心内存的申请即可,内存的释放由系统自动识别完成。
在进行垃圾回收时,不同的对象引用类型,GC会采用不同的回收时机

对象什么时候可以被垃圾回收

image.png

简单一句就是:如果一个或多个对象没有任何的引用指向它了,那么这个对象现在就是垃圾,如果定位了垃圾,则有可能会被垃圾回收器回收。
如果要定位什么是垃圾,有两种方式来确定,第一个是引用计数法,第二个是可达性分析算法

1 引用计数法

一个对象被引用了一次,在当前的对象头上递增一次引用次数,如果这个对象的引用次数为0,代表这个对象可回收
String demo = new String(“123”);

image.png

优点:

  • 实时性较高,无需等到内存不够的时候,才开始回收,运行时根据对象的计数器是否为0,就可以直接回收。
  • 在垃圾回收过程中,应用无需挂起。如果申请内存时,内存不足,则立刻报OOM错误。
  • 区域性,更新对象的计数器时,只是影响到该对象,不会扫描全部对象。
    缺点:
  • 每次对象被引用时,都需要去更新计数器,有一点时间开销。
  • 浪费CPU资源,即使内存够用,仍然在运行时进行计数器的统计。
  • 无法解决循环引用问题,会引发内存泄露。(最大的缺点)

2)可达性分析算法

现在的虚拟机采用的都是通过可达性分析算法来确定哪些内容是垃圾。
会存在一个根节点【GC Roots】,引出它下面指向的下一个节点,再以下一个节点节点开始找出它下面的节点,依次往下类推。直到所有的节点全部遍历完毕。

哪些可以作为根对象

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中 JNI(即一般说的 Native 方法)引用的对象
    核心是:判断某对象是否与根对象有直接或间接的引用,如果没有被引用,则可以当做垃圾回收

image.png
X,Y这两个节点是可回收的,但是并不会马上的被回收!! 对象中存在一个方法【finalize】。当对象被标记为可回收后,当发生GC时,首先会判断这个对象是否执行了finalize方法,如果这个方法还没有被执行的话,那么就会先来执行这个方法,接着在这个方法执行中,可以设置当前这个对象与GC ROOTS产生关联,那么这个方法执行完成之后,GC会再次判断对象是否可达,如果仍然不可达,则会进行回收,如果可达了,则不会进行回收。

finalize方法对于每一个对象来说,只会执行一次。如果第一次执行这个方法的时候,设置了当前对象与RC ROOTS关联,那么这一次不会进行回收。 那么等到这个对象第二次被标记为可回收时,那么该对象的finalize方法就不会再次执行了。

垃圾回收算法

1) 标记清除

标记清除算法,是将垃圾回收分为2个阶段,分别是标记和清除。
1.根据可达性分析算法得出的垃圾进行标记
2.对这些标记为可回收的内容进行垃圾回收
image.png
标记清除算法也是有缺点的:
效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要停止应用程序,对于交互性要求比较高的应用而言这个体验是非常差的。
(重要)通过标记清除算法清理出来的内存,碎片化较为严重,因为被回收的对象可能存在于内存的各个角落,所以清理出来的内存是不连贯的。

2) 复制

复制算法的核心就是,将原有的内存空间一分为二,每次只用其中的一块,在垃圾回收时,将正在使用的对象复制到另一个内存空间中,然后将该内存空间清空,交换两个内存的角色,完成垃圾的回收。
如果内存中的垃圾对象较多,需要复制的对象就较少,这种情况下适合使用该方式并且效率比较高,反之,则不适合。
image.png

1)将内存区域分成两部分,每次操作其中一个。
2)当进行垃圾回收时,将正在使用的内存区域中的存活对象移动到未使用的内存区域。当移动完对这部分内存区域一次性清除。
3)周而复始。
优点:

  • 在垃圾对象多的情况下,效率较高
  • 清理后,内存无碎片
    缺点:
    分配的2块内存空间,在同一个时刻,只能使用一半,内存使用率较低

3) 标记整理

标记压缩算法是在标记清除算法的基础之上,做了优化改进的算法。和标记清除算法一样,也是从根节点开始,对对象的引用进行标记,在清理阶段,并不是简单的直接清理可回收对象,而是将存活对象都向内存另一端移动,然后清理边界以外的垃圾,从而解决了碎片化的问题。
1)标记垃圾。
2)需要清除向右边走,不需要清除
3)清除边界以外的垃圾
image.png
优缺点同标记清除算法,解决了标记清除算法的碎片化的问题,同时,标记压缩算法多了一步,对象移动内存位置的步骤,其效率也有有一定的影响。与复制算法对比:复制算法标记完就复制,但标记整理算法得等把所有存活对象都标记完毕,再进行整理

分代收集

在java8时,堆被分为了两份:新生代和老年代【1:2】,在java7时,还存在一个永久代

image.png

对于新生代,内部又被分为了三个区域。Eden区,S0区,S1区【8:1:1】
当对新生代产生GC:MinorGC【young GC】
当对老年代代产生GC:Major GC
当对新生代和老年代产生FullGC: 新生代 + 老年代完整垃圾回收,暂停时间长,应尽力避免

工作机制

image.png
新创建的对象,都会先分配到eden区

image.png
当伊甸园内存不足,标记伊甸园与 from(现阶段没有)的存活对象
将存活对象采用复制算法复制到 to 中,复制完毕后,伊甸园和 from 内存都得到释放

image.png
经过一段时间后伊甸园的内存又出现不足,标记eden区域to区存活的对象,将存活的对象复制到from区

image.png
当幸存区对象熬过几次回收(最多15次),晋升到老年代(幸存区内存不足或者大对象会导致提前晋升)

MinorGC、 Mixed GC 、 FullGC的区别是什么

  • MinorGC【young GC】发生在新生代的垃圾回收,暂停时间短(STW)
  • Mixed GC 新生代 + 老年代部分区域的垃圾回收,G1 收集器特有
  • FullGC: 新生代 + 老年代完整垃圾回收,暂停时间长(STW),应尽力避免?
    名词解释:
    STW(Stop-The-World):暂停所有应用程序线程,等待垃圾回收的完成

JVM 有哪些垃圾回收器

实现了多种垃圾收集器,包括:

  • 串行垃圾收集器
  • 并行垃圾收集器
  • CMS(并发)垃圾收集器
  • G1垃圾收集器

串行垃圾收集器

Serial和Serial Old串行垃圾收集器,是指使用单线程进行垃圾回收,堆内存较小,适合个人电脑

  • Serial 作用于新生代,采用复制算法
  • Serial Old 作用于老年代,采用标记-整理算法

垃圾回收时,只有一个线程在工作,并且java应用中的所有线程都要暂停(STW),等待垃圾回收的完成。

image.png

并行垃圾收集器

Parallel New和Parallel Old是一个并行垃圾回收器,JDK8默认使用此垃圾回收器

  • Parallel New作用于新生代,采用复制算法
  • Parallel Old作用于老年代,采用标记-整理算法
    垃圾回收时,多个线程在工作,并且java应用中的所有线程都要暂停(STW),等待垃圾回收的完成。

image.png

CMS(并发)垃圾收集器

CMS全称 Concurrent Mark Sweep,是一款并发的、使用标记-清除算法的垃圾回

CMS全称 Concurrent Mark Sweep,是一款并发的、使用标记-清除算法的垃圾回收器,该回收器是针对老年代垃圾回收的,是一款以获取最短回收停顿时间为目标的收集器,停顿时间短,用户体验就好。其最大特点是在进行垃圾回收时,应用仍然能正常运行
image.png

G1垃圾回收器

  • 应用于新生代和老年代,在JDK9之后默认使用G1
  • 划分成多个区域,每个区域都可以充当 eden,survivor,old, humongous,
  • 其中 humongous 专为大对象准备
  • 采用复制算法
  • 响应时间与吞吐量兼顾
  • 分成三个阶段:新生代回收、并发标记、混合收集
  • 如果并发失败(即回收速度赶不上创建新对象速度),会触发 Full GC
    image.png

强引用、软引用、弱引用、虚引用的区别

  • 强引用:
    只有所有 GC Roots 对象都不通过【强引用】引用该对象,该对象才能被垃圾回收

  • 软引用
    软引用:仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次出发垃圾回收

  • 弱引用:
    仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象

  • 虚引用:必须配合引用队列使用,被引用对象回收时,会将虚引用入队,由Reference Handler 线程调用虚引用相关

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1143816.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【luckfox】添加压力传感器hx711

文章目录 前言一、参考资料二、电路图三、驱动四、makefile——添加驱动五、dts——使能gpio5.1 参考5.2 改动1—— hx117节点5.3 改动2——引脚节点5.4 已经被定义的引脚5.5 gpio源码 六、改动总结——使能hx711七、验证驱动添加八、编写测试文件8.1 测试代码8.2 配置编译环境…

设计模式——单例模式详解

目录 设计模式类型单例模式单例模式方式饿汉式静态常量方式静态代码块形式 懒汉式线程不安全(不推荐)懒汉式优化(不推荐) 双重检查(推荐方式)静态内部类(推荐方式)枚举方式&#xff…

LeetCode 1465. 切割后面积最大的蛋糕【贪心,数组,排序】1444

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…

探秘Kafka背后的幕后机关,揭示消息不丢失或重复的原理与实践经验

背景 相信大家在工作中都用过消息队列,特别是 Kafka 使用得更是普遍,业务工程师在使用 Kafka 的时候除了担忧 kafka 服务端宕机外,其实最怕如下这样两件事。 消息丢失。下游系统没收到上游系统发送的消息,造成系统间数据不一致。…

基于springboot实现校园志愿者管理系统项目【项目源码+论文说明】

基于springboot实现校园志愿者管理系统演示 摘要 随着信息化时代的到来,管理系统都趋向于智能化、系统化,校园志愿者管理系统也不例外,但目前国内仍都使用人工管理,市场规模越来越大,同时信息量也越来越庞大&#xff…

VMware 16开启虚拟机电脑就蓝屏W11解决方法

问题现象 解决方法 控制面板->程序->启用或关闭windows功能->勾选虚拟机平台->重启

VTKQT 3D交互---[3]降低抬高功能PushAndPull

前言:在医疗的应用中,有时会需要手动去修改模型,比如3-matic软件中的LocalSmoothing和PushAndPull功能。该博文主要记录降低抬高PushAndPull功能。

4 H3C网络设备模拟器

如果大家没有硬件,但是也想做一下组网,可以使用H3C提供的网络模拟器。因为我使用的是mac,所以将软件安装到虚拟机里。安装好之后可以看到如下结构: 交换机工作原理 在使用模拟器前,我们先学习一下交换机的工作原理。 …

深入剖析SQL与NoSQL的优劣势,帮你决定最佳数据存储方案

你是否在为系统的数据库来一波大流量就几乎打满 CPU,日常 CPU 居高不下烦恼?你是否在各种 NoSQL 间纠结不定,到底该选用哪种最好?今天的你就是昨天的我,这也是我写这篇文章的初衷。 作为互联网从业人员,我们要知道关系型数据库…

VMware16,运行虚机后E盘下就会产生一个奇怪的文件夹

问题现象: VMware16,运行虚机后E盘下就会产生一个奇怪的文件夹,是乱码的 问题原因: 虚机安装路径存在中文 解决方法: 删除乱码文件夹 一:是否有中文路径,有的话改为英文路径 二&#xff1…

HED边缘检测

HED边缘检测 HED边缘检测,得到模型后,可以用OPENCV调用,不需要其他依赖,C/PYTHON/ANDROID都可以实现,效果如下:

Ubuntu安装docker,并换镜像源详细教程,建议收藏

文章目录 添加docker官方的GPG密钥将docker仓库添加到apt源安装docker检查docker换源 添加docker官方的GPG密钥 sudo apt-get updatesudo apt-get install ca-certificates curl gnupgsudo install -m 0755 -d /etc/apt/keyringscurl -fsSL https://download.docker.com/linux…

GB/T28181流媒体相关协议详解

GB/T28181流媒体相关协议详解 文章目录 GB/T28181流媒体相关协议详解1 GB/T28181协议中使用的应用层协议介绍2 实时视频点播协议交互流程2.1 设备注册2.2 设备保活2.3 视频播放 总结 本文主要主要针对28181协议中视频流的部分,来阐述视频流通过28181协议如何进行视频…

解密RocketMq的运行机制,带你玩转分布式消息通信

一、 MQ背景&选型 消息队列作为高并发系统的核心组件之一,能够帮助业务系统解耦提升开发效率和系统稳定性。主要具有以下优势: 削峰填谷(主要解决瞬时写压力大于应用服务能力导致消息丢失、系统奔溃等问题)系统解耦&#xf…

Faster R-CNN(2016.1)

文章目录 摘要引言过去计算proposals的算法我们提出的 相关工作Object ProposalsDeep Networks for Object Detection Faster R-CNNRegion Proposal NetworksAnchorsTranslation-Invariant AnchorsMulti-Scale Anchors as Regression References多尺度预测有两种流行的方法我们…

云计算未来展望:边缘计算、量子计算与AI

文章目录 边缘计算:数据处理的新时代应用领域挑战与机遇 量子计算:超越传统计算的新范式量子比特应用前景挑战与机遇 人工智能:云计算的动力云中的AI应用领域挑战与机遇 结语 🎉欢迎来到云计算技术应用专栏~云计算未来展望&#x…

Vue学习之样式汇总

Vue学习之样式汇总 一 二者左右排版 案例 说明:头部一左一右排版,内容一左一右两个排版,公告栏文字超过点点点显示 代码实现 说明: (1)头部实现一左一右排版需要使用一下两个样式 display: flex;justify-…

4、QtCharts 做心电图

文章目录 ui界面核心代码全部代码 ui界面 核心代码 void Dialog::slot_timer() {qreal xOffset0.f;//x的偏移量,推进的距离qreal dIncrease10;//增加量//数据for(int i0;i<10;i){m_xdIncrease;xOffsetdIncrease;m_splineSerise->append(m_x,qrand()%10);//根据实际情况删…

IDEA新建maven项目,使用mybatis操作数据库完整过程

IDEA新建maven项目&#xff0c;使用mybatis操作数据库完整过程 一、IDEA新建maven项目二、配置mybatis三、创建表对应实体类四、创建mapper接口五、使用mybatis操作数据库 前提&#xff1a; 这个教程是在maven项目中使用mybatis进行数据库操作&#xff0c;不是在spring boot项目…

51单片机复位电容计算与分析(附带Proteus电路图)

因为iC x (dU/dt).在上电瞬间&#xff0c;U从0变化到U,所以这一瞬间就是通的&#xff0c;然后这就是一个直流回路&#xff0c;因为电容C直流中是断路的&#xff0c;所以就不通了。 然后来分析一下这个电容的电压到底是能不能达到单片机需要的复位电压。 这是一个线性电容&…