JVM知识面试题

本文详细介绍了JVM(Java虚拟机)的基础知识,包括JVM、JDK和JRE的区别,Java程序的运行过程,JVM的组成和运行时数据区。此外,还讲解了类加载过程、垃圾回收机制、内存区域的划分以及各种垃圾收集器的工作原理。通过对这些概念的深入理解,有助于优化Java程序的性能。
摘要由CSDN通过智能技术生成

一、JVM,JDK,JRE的区别

1、JVM:是用于运行Java字节码的虚拟机,包括一套字节码指令集、一组程序寄存器、一个虚拟机栈、一个虚拟机堆、一个方法区和一个垃圾回收器。
2、JRE:可以把JAVA类库的API中的Java SE API字节和Java虚拟机这俩部分统称为JRE,JRE是支持Java程序运行的标准环境。
3、JDK:我们可以把Java程序设计语言、Java虚拟机、Java类库这三部分统称为JDK,JDK是用于支持Java程序开发的最小环境。

二、Java程序的具体运行过程

1、Java源文件被编译器编译成字节码文件。
2、JVM将字节码文件编译成相应操作系统的机器码。
3、机器码调用相应操作系统的本地方法库执行相应的方法。

三、JVM组成部分

Java虚拟机包括一个类加载器子系统(Class Loader SubSystem)、运行时数据区(Runtime Data Area)、执行引擎和本地接口库(Native Interface Library)。
在这里插入图片描述
1、类加载器子系统用于将编译好的.Class文件加载到JVM中;
2、运行时数据区用于存储在JVM运行过程中产生的数据,包括程序计数器、方法区、本地方法区、虚拟机栈和虚拟机堆;
3、执行引擎包括即时编译器和垃圾回收器,即时编译器用于将Java字节码编译成具体的机器码,垃圾回收器用于回收在运行过程中不再使用的对象;
4、本地接口库用于调用操作系统的本地方法库完成具体的指令操作。

四、JVM运行时数据区

1、程序计数器:线程私有,唯一无内存溢出问题
程序计数器是一块很小的内存空间,用于存储当前运行的线程所执行的字节码的行号指示器。每个运行中的线程都有一个独立的程序计数器,在方法正在执行时,该方法的程序计数器记录的是实时虚拟机字节码指令的地址;如果该方法执行的是Native方法,则程序计数器的值为空。
2、虚拟机栈:线程私有,描述Java方法的执行过程。
虚拟机栈是描述Java方法的执行过程的内存模型,它在当前栈帧中存储了局部变量表、操作数栈、动态链接、方法出口等信息。同时,栈帧用来存储部分运行时数据及其数据结构,处理动态链接方法的返回值和异常分派。
栈帧用来记录方法的执行过程,在方法被执行时虚拟机会为其创建一个与之对应的栈帧,方法的执行和返回对应栈帧在虚拟机栈中的入栈和出栈。无论方法是正常运行完成还是异常完成(抛出了在方法内未被捕获的异常),都视为方法运行结束。
3、本地方法区:线程私有
本地方法栈为Native方法服务。
4、堆:也叫作运行时数据区,线程共享
在JVM运行过程中创建的对象和产生的数据都被存储在堆中,堆是被线程共享的内存区域,也是垃圾收集器进行垃圾回收的最主要的存在区域。由于现代JVM采用分代收集算法,因此Java堆从GC(Garbage Collection,垃圾回收)的角度还可以细分为新生代、老年代、永久代。
5、方法区:线程共享
方法区也被称为永久代,用于存储常量,静态变量、类信息、即使编译器编译后的机器码、运行时常量池等数据。

五、JVM的内存区域

JVM的内存区域分为线程私有区域(程序计数器、虚拟机栈、本地方法区)、线程共享区域(堆、方法区)和直接内存。
1、线程私有区域的生命周期与线程相同,随线程的启动而创建,随线程的结束而销毁。在JVM内部,每个线程都与操作系统的本地线程直接映射,因此线程私有区域的存在与否和本地线程的启动和销毁对应。
2、线程共享区域随虚拟机的启动而创建,随虚拟机的关闭而销毁。
3、直接内存也叫作对外内存,它并不是JVM运行时数据区的一部分,但在并发编程中被频繁使用。

六、队列,堆和栈的区别

七、双亲委派模型

JVM通过双亲委派机制对类进行加载。双亲委派机制指一个类在收到类加载请求后不会尝试自己加载这个类,而是把该类加载请求向上委派给其父类去完成,其父类在接收到该类加载请求后又会将其委派给自己的父类。以此类推,这样所有的类加载请求都被向上委派到启动类加载器中。若父类加载器在接收到类加载请求后发现自己也无法加载该类(通常原因是该类的Class文件在父类的类加载路径中不存在),则父类会将该信息反馈给子类并向下委派加载器加载到该类,直到该类被成功加载,若找不到该类,则JVM会抛出ClassNotFound异常。

双亲委派机制的核心是保障类的唯一性和安全性。

双亲委派类加载机制的类加载过程:
1、将自定义加载器挂载到应用程序类加载器。
2、应用程序类加载器将类加载请求委托给扩展类加载器。
3、扩展类加载器将类加载请求委托给启动类加载器
4、启动类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由扩展类加载器加载。
5、扩展类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由应用程序类加载器加载。
6、应用程序类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由自定义加载器加载。
7、在自定义加载器下查找并加载用户指定目录下的Class文件,如果在自定义加载路径下未找到目标Class文件,则抛出ClassNotFound异常。

八、类装载的执行过程

JVM的类加载分为5个阶段:加载、验证、准备、解析、初始化。
1、加载
指JVM读取Class文件,并且根据Class文件描述创建java.lang.Class对象的过程。
2、验证
主要用于确保Class文件符合当前虚拟机的要求,保障虚拟机自身的安全,只有通过验证的Class文件才能被JVM加载。
3、准备
主要工作是在方法区中为类变量分配内存空间并设置类中变量的初始值。
4、解析
JVM会将常量池中的符号引用替换为直接引用。
5、初始化
主要通过执行类构造器的< client>方法为类进行初始化。

九、怎么判断对象是否可以被回收

Java采用引用计数法和可达性分析来确定对象是否应该被回收,其中,引用计数法容易产生循环引用问题,可达性分析通过根搜索算法来实现。
在这里插入图片描述

十、Java中都有哪些引用类型

在Java中一切皆对象,对象的操作是通过该对象的引用实现的,Java中的引用类型有4种:
(1)强引用:在Java中最常见的就是强引用。在把一个对象赋给一个引用变量时,这个引用变量就是一个强引用。
(2)软引用:软引用通过SoftReference类实现。如果一个对象只有软引用,则在系统内存空间不足时该对象将被回收。
(3)弱引用:弱引用通过WeakReference类实现,如果一个对象只有弱引用,则在垃圾回收过程中一定会被吸收。
(4)虚引用:虚引用通过PhantomReference类实现,虚引用和引用队列联合使用,主要用于跟踪对象的垃圾回收状态。

十一、JVM中有哪些垃圾回收算法

在这里插入图片描述

十二、JVM有哪些垃圾收集器

在这里插入图片描述
在这里插入图片描述

十三、CMS垃圾收集器

CMS垃圾收集器是为老年代设计的垃圾收集器,其主要目的是使用最短的垃圾回收停顿时间完成垃圾回收,基于多线程的标记清除算法实现,以便在多线程并发环境下以最短的垃圾收集停顿时间提高系统的稳定性。
CMS的工作机制相对复杂,垃圾回收过程包含如下4个步骤:
1、初始标记:只标记和GC Roots直接关联的对象,速度很快,需要暂停所有工作线程。
2、并发标记:和用户线程一起工作,执行GC Roots跟踪标记过程,不需要暂停工作线程。
3、重新标记:在并发标记过程中用户线程继续运行,导致在垃圾回收过程中部分对象的状态发生变化,为了确保这部分对象的状态正确性,需要对其重新标记并暂停工作线程。
4、并发清除:和用户线程一起工作,执行清除GC Roots不可达对象的任务,不需要暂停工作线程。
CMS垃圾收集器在和用户线程一起工作时(并发标记和并发清除)不需要暂停用户线程,有效缩短了垃圾回收时系统的停顿时间,同时由于CMS垃圾收集器和用户线程一起工作,因此其并行度和效率也有很大提升。

十四、新生代垃圾收集器和老年代垃圾收集器的区别

新生代主要存储短生命周期的对象,适合使用复制算法进行垃圾回收;老年代主要存储长生命周期的对象,适合使用标记整理算法进行垃圾回收。

十五、新生代回收:Eden区、SurvivorTo区和SurvivorFrom区

由于JVM会频繁创建对象,所以新生代会频繁触发MinorGC进行垃圾回收。新生代又分为Eden区、SurvivorTo区和SurvivorFrom区,如下所述:
(1)Eden区:Java新创建的对象首先会被存放在Eden区,如果新创建的对象属于大对象,则直接将其分配到老年代。大对象的定义和具体的JVM版本、堆大小和垃圾回收策略有关,一般为2KB~128KB,可通过XX:PretenureSizeThreshold设置其大小。在Eden区的内存空间不足时会触发MinorGC,对新生代进行一次垃圾回收。
(2)SurvivorTo区:保留上一次MinorGC时的幸存者。
(3)SurvivorFrom区:将上一次MinorGC时的幸存者作为这一次MinorGC的被扫描者。
新生代的GC过程叫作MinorGC,采用复制算法实现,具体过程如下:
(1)把在Eden区和SurvivorFrom区中存活的对象复制到SurvivorTo区。如果某对象的年龄达到老年代的标准(对象晋升老年代的标准由XX:PretenureSizeThreshold设置,默认为15),则将其复制到老年代,同时把这些对象的年龄加1;如果SurvivorTo区的内存空间,则也直接将其复制到老年代;如果对象属于大对象,则也直接将其复制到老年代。
(2)清空Eden区和SurvivorFrom区中的对象
(3)将SurvivorTo区和SurvivorFrom区互换,原来的SurvivorTo区成为下一次GC时的SurvivorFrom区。

十六、老年代回收

老年代主要存放长生命周期的对象和大对象。老年代的GC过程叫作MajorGC。在老年代,对象比较稳定,MajorGC不会被频繁触发。在进行MajorGC前,JVM会进行一次MinorGC,在MinorGC过后仍然出现老年代且当老年代空间不足或无法找到足够大的连续内存空间分配给新创建的大对象时,会触发MajorGC进行垃圾回收,释放JVM的内存空间。
MajorGC采用标记清除算法,该算法首先会扫描所有对象并标记存活的对象,然后回收未标记的对象,并释放内存空间。
MajorGC的标记清除算法容易产生内存碎片。在老年代没有内存空间可分配时,抛出Out Of Memory异常。

十七、永久代

GC不会在程序运行期间对永久代的内存进行清理,导致了永久代的内存会随着加载的Class文件的增加而增加,在加载的Class文件过多时会抛出Out Of Memory异常。
在Java8中永久代已经被元数据区取代。元数据区的作用和永久代相似,二者最大的区别在于:元数据区并没有使用虚拟机的内存,而是直接使用操作系统的本地内存。

十八、JVM调优工具

十九、JVM调优的参数都有哪些

二十、OSGI

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值