Java Interview(JVM)

目录

一、说一说JVM的内存模型

在这里插入图片描述

二、JAVA类加载的全过程是怎么样的?什么是双亲委派机制?有什么作用?

1、双亲委派机制

Java的类加载器有以下几种:AppClassLoader、ExtClassLoader、BootStrap ClassLoader。

类加载器的继承关系:AppClassLoader,ExtClasLoader -》URLClassLoader -》SecureClassLoader -》ClassLoader

以上三种类加载器,每一种类加载都有对应的加载目录;对加载过的类,都是有一个缓存的

双亲委派:类加载的时候,向上委托类的查找,向下委托类的加载;作用:保护JAVA的层的类不会被应用程序覆盖
在这里插入图片描述

2、类加载的全过程

1、加载:将Java的字节码数据加载到JVM内存中,并映射成JVM认可的数据结构
2、连接:分为三步:
验证:检查加载到的字节信息是否符合JVM的规范
准备:在JVM堆中创建类或者接口的静态变量,并赋默认值
解析:将JVM栈中的引用变量指向JVM堆中的数据,变成直接引用
3、进行类的初始化

三、一个对象从加载到JVM,再被GC清除,都经历了什么过程?

1、用户创建一个对象的时候,先要根据类的ClassPointer去方法区找到对应对象的类型,然后再创建对象

2、JVM要实例化一个对象,首先要在堆中先创建一个对象,栈中的引用变量指向该对象

3、对象首先会分配到堆中的Eden中,在执行MinorGC()方法的时候,如果对象存活则被移入Survivor区;如果对象一直存活则在Survivor的两个区来回移动,并且年龄+1;

4、对象的markword有4bits记录了对象的年龄;如果年龄超过15,则对象被移入到老年代

5、方法结束后,栈中的引用变量将被移除

6、堆中的对象,经过FullGC(),就会标记为垃圾,然后被GC线程清除

四、如何确定一个对象是不是垃圾?什么是GC Root?

有两种定位垃圾的方式:

1、引用计数:给堆内存中的每个对象记录一个引用个数,为0证明是垃圾。这是早期JDK使用的方式,缺陷:没法解决循环引用的问题,该回收的内存没办法回收,从而导致内存泄露的问题
2、根可达算法:从GC Root开始一直向下查找引用,找不到的就是垃圾

哪些是GC Root?

栈中:JVM栈,原生Native栈,class类,runtime constant pool,static reference静态变量

五、JVM有哪些垃圾回收算法?

MarkSweep 标记清除:

在这里插入图片描述
将垃圾内存标记出来,然后进行内存的回收;
这种算法简单,但是有一个缺点,就是会产生大量的内存碎片

Copying 拷贝算法:

在这里插入图片描述
将内存分为两半,每次只使用其中一半;将一半内存中所有存活对象复制到另一半,从而自己这一半的内存就可以直接被全部回收了。
这种算法能避免内存碎片,但是内存利用率低,而且算法运行效率与存活对象的数量有关;需要被复制的存活对象越多时,算法的运行效率越低

MarkCompact标记压缩算法:

在这里插入图片描述
首先将垃圾对象进行标记,然后将所有存活对象移动到内存的一端,从而可将边界以外未使用的其他内存全部进行回收和清除。
这种算法看起来效果最好,但是算法复杂度也比较高

三种算法各有各的优缺点和适用场景

六、JVM有哪些垃圾回收器?他们都是怎么工作的?什么是STW?他们都发生在哪些阶段?什么是三色标记?如何解决错标记和漏标记的问题?为什么需要设计这么多的垃圾回收器?

1、STW: Stop The World

将JVM内存进行冻结,在冻结的状态下,Java的所有线程(GC线程除外)都是停止的。Native方法可以执行,但他们不能与JVM进行交互。GC各种算法优化的重点,就是减少STW;这也是我们进行JVM调优的重点。

2、JVM的垃圾回收器

在这里插入图片描述

3、分代算法的分类:

Serial串行:

在这里插入图片描述
线程并行执行时,需要垃圾回收时启动STW,回收完之后再继续执行之前的线程。
只有一个线程执行GC,这种方法在多CPU架构下性能下降很严重

Parallel并行:

在这里插入图片描述
在串行的基础上,使用的STW多线程执行GC的机制;PS+PO这种组合是JDK1.8默认的垃圾回收器。在多CPU的架构下,性能比Serial高很多。

CMS: Concurrent Mark Sweep并发标记清除

在这里插入图片描述
核心思想:将STW打散,允许一部分GC线程与用户线程并发执行。整个GC过程分为四个阶段
初始标记:STW只标记出GC Root直接引用的对象
并发标记:允许部分GC线程在程序执行的过程中标记其他对象
重新标记:STW在上一个阶段程序并发执行的过程中的对象进行重新标记。
并发清除:并行;将产生的垃圾清除。并发清除的过程中,应用程序又会不断产生新的垃圾,这些垃圾被称为浮动垃圾。这些垃圾要留到下一次GC过程中清除

G1: Garbage First垃圾优先

在这里插入图片描述
他的内存模型是实际上不分代,但是逻辑上市分代的。在内存模型中,堆内存不再被划分为老年代和新生代,而是被分为一个个的Region,每一个Region可以属于不同的年代。
G1可以分为四个阶段:
第一:初始标记 标记出GC Root直接引用的对象
第二:标记Region 通过RSet标记出上一个阶段标记的Region引用到的Old区的Region
第三:并发标记阶段 跟CMS差不多 只不过只扫描第二步被标记出来的Old区的Region
第四:重新标记 和CMS重新标记类似
第五:垃圾清理 与CMS不同,G1采用的拷贝算法;直接将整个Region的对象拷贝到另一个Region中,清除原来的Region;并且G1只选择垃圾较多的Region进行清理,并不会完全清理所有Region中的垃圾空间。

4、三色标记

CMS的核心算法就是三色标记
三色标记是一种逻辑上的抽象
黑色:表明对象本身和成员变量都已经被标记
灰色:表明只有对象本身被标记,成员变量没有被标记
白色:表明对象和成员变量都没有被标记

漏标记:

原来的对象引用关系如下:
在这里插入图片描述
经过CMS的并发标记阶段之后,引用关系可能发生改变:
在这里插入图片描述
这时候,A为黑色,不会去寻找C;B为灰色,但是没有成员变量了。那么对象C则为根不可达,会被GC回收。程序中A的引用关系就乱套了。

解决办法:CMS通过增量标记increment update来解决漏标的问题

七、如何进行JVM的调优?JVM的参数有哪些?如果一个Java程序,每运行一段时间后就会变得非常卡顿,你如何解决?

通过定制JVM运行参数来提高Java的运行速度

JVM参数大致分为3类:

标准指令:-开头,所有HotSpot都支持的参数。可用java -help打印
非标准指令:-X开头,和不同的Hotspot版本对应,用java -X打印
不稳定参数:-XX开头,和不同的Hotspot版本对应,而且变化非常大,详细的文档资料少。
例如:java -XX:PrintCommandLineFlags:打印当前命令的不稳定参数
java -XX: PrintFlagsInitial: 打印当前命令不稳定参数的初始化值
java -XX: PrintFlagsFinal: 打印当前命令不稳定参数最终生效的实际值

可以使用java -jar arthas-boot.jar查看当前线程的内存执行情况。通过help命令可以查看其他指令;比如:thread -b查看当前进程中是否存在死锁的线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值