JVM经典面试题总结(下)

本文总结了JVM的经典面试问题,涵盖了对象在内存中的分配策略,包括对象优先在Eden分配和大对象直接晋升至老年代的情况。讨论了分代垃圾回收的过程,以及JVM永久代的垃圾回收。介绍了各种垃圾收集器,如Serial、ParNew、ParallelScavenge、CMS和G1,以及它们的特点和参数配置。此外,还涉及了类加载器的概念和双亲委托机制,以及JVM性能调优的相关命令和参数。
摘要由CSDN通过智能技术生成

JVM经典面试题总结

上篇请阅读:JVM经典面试题总结(上)

一、对象分配

1.对象在内存中是如何进行分配的?

1.1对象优先在Eden分配

对象优先在『伊甸园』分配,当『伊甸园』没有足够的空间时,触发 ‘MinorGC’(小范围的GC)

情况一:伊甸园的内存空间足够,不会发生’Minor GC’
在这里插入图片描述情况二:伊甸园的空间不够了
在这里插入图片描述垃圾回收线程启动,进行垃圾回收,此时会触发"stop the world"(停止所有用户线程)

在这里插入图片描述Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄最多到一定值(最大值是15,对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁)(年龄阈值,可以通过XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有
达到阈值的对象会被复制到“To”区域。
在这里插入图片描述"From"和"To"会交换他们的角色,下一次垃圾回收的时候也是从Eden将存活的对象复制到TO区

在这里插入图片描述Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
jvm参数设置

-XX:+UseSerialGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -
Xloggc:./gc.log -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
-XX:+UseSerialGC 是指使用 Serial + SerialOld 回收器组合
-XX:+PrintGCDetails -verbose:gc 是指打印 GC 详细信息
-XX:+PrintGCTimeStamps 打印gc日志的时间戳
-Xloggc:./gc.log 将gc日志输出到一个日志文件中
-Xms20M -Xmx20M -Xmn10M 是指分配给JVM的最小,最大以及新生代内存
-XX:SurvivorRatio=8 是指『伊甸园』与『幸存区 From』和『幸存区 To』比例为 8:1:1

1.2大对象直接晋升至老年代

当对象太大,伊甸园包括幸存区都存放不下时,这时候老年代的连续空间足够,此对象会直接晋升至老年代,不会发生 GC
在这里插入图片描述

2.对象是怎么从年轻代进入老年代的?

  1. 如果对象够老,会通过提升(Promotion)进入老年代,这一般是根据对象的年龄进行判断的。
  2. 、动态对象年龄判定。有的垃圾回收算法,比如G1,并不要求age必须达到15才能晋升到老年代,它会使用一些动态的计算方法。
  3. 超出某个大小的对象将直接在老年代分配。不过这个值默认为0,意思是全部首选Eden区进行分配。

3.简单描述一下(分代)垃圾回收的过程?

在这里插入图片描述

分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是2/3。
新生代使用的是复制算法,新生代里有3个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,它的执行流程如下:
当年轻代中的Eden区分配满的时候,就会触发年轻代的GC(Minor GC)。具体过程如下:
1、在Eden区执行了第一次GC之后,存活的对象会被移动到其中一个Survivor分区(以下简称to)
2、From区中的对象根据对象的年龄值决定去向,达到阈值15移动到老年代,没有达到复制到to区域(复制算法)
3、在把Eden和to区中的对象清空掉

4.JVM的永久代中会发生垃圾回收么??

永久代会触发垃圾回收的,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。
注:Java 8 中已经移除了永久代,新加了一个叫做元数据区(Metaspace)的内存区。

二、垃圾收集器

1.常见的垃圾收集器都有哪些?

在这里插入图片描述不同的垃圾收集器,作用的堆内存空间是不一样的;上面的 serial , parnew , Paraller Scavenge 是新生代的垃圾回收器;CMS , Serial Old ,Paralle Old是老年代的垃圾收集器 , G1垃圾收集器可以作用于新生代和老年代; 连线表示垃圾收集器可以搭配使用;

1.1 Serial

特点:

  1. Serial是一个单线程的垃圾收集器
  2. “Stop The World”,它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。在用户不可见的情况下把用户正常工作的线程全部停掉
  3. 使用场景:多用于桌面应用,Client端的垃圾回收器
  4. 桌面应用内存小,进行垃圾回收的时间比较短,只要不频繁发生停顿就可以接受
    Serial Old收集器是Serial的老年代版本和Serial一样是单线程,使用的算法是"标记-整理"
    在这里插入图片描述

1.2 ParNew

ParNew 收集器其实就是 Serial 收集器的多线程版本

在这里插入图片描述1. 会触发stop the world
2. 多线程方式进行垃圾回收
它是许多运行在 Server 模式下的虚拟机中首选的新生代收集器
注意:如果是单核cpu即使使用该垃圾回收器也无法提高执行效率

1.3 Parallel Scavenge

Parallel Scavenge 收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器

特点:由于与吞吐量关系密切,Parallel Scavenge 收集器也经常称为“吞吐量优先”收集器,所谓吞吐量就是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值,即吞吐量=运行用户代码时
间/(运行用户代码时间+垃圾收集时间),虚拟
机总共运行了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是 99%
应用场景: 高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
Parallel old收集器Parallel Scavenge收集器的老年代版本,使用多线程+标记整理算法

1.4 CMS(重点)

CMS (Concurrent Mark Sweep)收集器是-种以获取最短回收停顿时间为目标的收集器。

特点:

  1. CMS 收集器是基于“标记清除”算法实现的
  2. 目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。
    在这里插入图片描述步骤流程
  • 初始标记(CMS initial mark) -------- 标记一下 GC Roots 能直接关联到的对象,速度很快(stopthe world)
  • 并发标记(CMS concurrent mark) -------- 对初始标记标记过的对象,进行trace(进行追踪,得到所有关联的对象,进行标记)
  • 重新标记(CMS remark) -------- 为了修正并发标记期间因用户程序导致标记产生变动的标记记录(stop the world)
  • 并发清除(CMS concurrent sweep)

缺点:会产生垃圾碎片

1.5 G1

概述: G1是一个分代的,并行与并发的"标记整理"垃圾回收器。 它的设计目标是为了适应现在不断扩大的内存和不断增加的处理器数量,进一步降低暂停时间(pause time),同时兼顾良好的吞吐量。

相比于CMS:

  1. G1垃圾回收器使用的是"标记-整理",因此其回收得到的空间是连续的。
  2. G1回收器的内存与CMS回收器要求的内存模型有极大的不同。G1将内存划分一个个固定大小的region,每个region可以是年轻代、老年代的一个。内存的回收是以region作为基本单位的;
    在这里插入图片描述

2.你都用过G1垃圾回收器的哪几个重要参数?

-XX:MaxGCPauseMillis
暂停时间,默认值200ms。这是一个软性目标,G1会尽量达成,如果达不成,会逐渐做自我调整。
 -XX:G1HeapRegionSize
Region大小,若未指定则默认最多生成2048块,每块的大小需要为2的幂次方,如1,2,4,8,16,32,最大
值为32M。
 -XX:G1NewSizePercent-XX:G1MaxNewSizePercent
新生代比例有两个数值指定,下限:-XX:G1NewSizePercent,默认值5%,上限:-
XX:G1MaxNewSizePercent,默认值60%

3.生产上如何配置垃圾收集器的?

在这里插入图片描述1. 首先是内存大小问题,基本上每一个内存区域我都会设置一个上限,来避免溢出问题,比如元空间。通常,堆空间我会设置成操作系统的2/3(这是想给其他进程和操作系统预留一些时间),超过8GB的堆优先选用G1。
2. 接下来,我会对JVM进行初步优化。比如根据老年代的对象提升速度,来调整年轻代和老年代之间的比例。
3. 再接下来,就是专项优化,主要判断的依据就是系统容量、访问延迟、吞吐量等。我们的服务是高并发的,所以对STW的时间非常敏感。我会通过记录详细的GC日志,来找到这个瓶颈点,借用gceasy(重点)gceasy这样的日志分析工具,很容易定位到问题。之所以选择采用工具,是因为gc日志看起来实在是太麻烦了,gceasy号称是AI学习分析问题,可视化做的较好。
在这里插入图片描述

三、类加载器

1.什么是类加载器,类加载器有哪些?

类加载器的作用:负责将的class文件加载到java虚拟机中,并为之创建一个Class对象从Java虚拟机的角度来讲,只存在如下两种不同的类加载器

  1. 启动类加载器(Bootstrap ClassLoader), 这个类加载器使用C++语言实现,是虚拟机自身的一部
  2. 其他类加载器,这些类加载器都由Java语言实现,独立于虚拟机外部,并且全部都继承自抽象类(java.lang.ClassLoader)

从Java开发的角度来讲,类加载器还可以划分的更细致一下,绝大部分Java程序都会使用到以下3种系统提供的类加载器:

  1. 启动类加载器(Bootstrap class loader):它是虚拟机的内置类加载器,通过表示为null
  2. 平台类加载器(Platform class loader) :它是平台类加载器; 负责加载JDK中一些特殊的模块;
  3. 系统类加载器(System class loader) :它也被称为应用程序类加载器, 它负责加载用户类路径上所指定的类库,一般情况下这个就是程序中默认的类加载器

2. Java的双亲委托机制是什么?

我们的应用程序都是由这三种类加载器互相配合进行加载的,如果有必要,还可以加入自定义的类加载器。这些类加载器之间的层次关系一般会如下图所示

在这里插入图片描述上图所展示的类加载器之间的这种层次关系,就称之为类加载器的双亲委派模型。双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应该有自己的父类加载器。这里的类加载器的父子关系不是真正物理意义上的继承,而是逻辑上的继承。
工作过程
双亲委派模型的工作过程是:

如果一个类加载器收到了类加载的请求,它首先不会自己尝试加载这个类,而是把这请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传说到顶层的启动类加载器中,只有当父类加载器返回自己无法完成这个加载请求(它的搜索返回中没有找到所需的类)时,子类加载器才会尝试自己去加载。

四、性能调优

1调优命令有哪些?

  1. jps,JVM Process Status Tool显示指定系统内所有的HotSpot虚拟机进程。

  2. jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运
    行数据。查询帮助文档:jstat -options
    在这里插入图片描述在这里插入图片描述

  3. jmap,JVM Memory Map命令用于查看堆内存的分配情况以及生成heap dump文件
    查询帮助文档:jmap -h
    示例1:jmap -heap 33193 查询堆内存的分配情况
    示例2:jmap -dump:format=b,file=thread-cup.log 33193

  4. jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的
    分析结果后,可以在浏览器中查看
    查询帮助文档:jhat -h
    示例:jhat -J-Xmx512M thread-cup.log
    在这里插入图片描述

  5. jstack,用于生成java虚拟机当前时刻的线程快照。
    查看帮助文档:jstack -h
    示例:jstack -l 33193

  6. jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。
    查看帮助文档:jinfo -h
    示例:jinfo -flags 33193
    在这里插入图片描述

2.你知道哪些JVM性能调优参数?

  1. 设定堆内存大小:
    -Xms 设置最小堆内存大小(不能小于1024K); -Xms 堆内存初始大小,可以通过jmap工具进行查看
    -Xmx 设置最大堆内存大小(不能小于1024K); -Xmx 堆内存最大值,可以通过jmap工具进行查看
  2. 设定新生代大小:
    -XX:NewSize:新生代大小
    -XX:NewRatio 新生代和老生代占比
  3. -XX:SurvivorRatio:伊甸园空间和幸存者空间的占比
  4. 设定垃圾回收器
    年轻代用 -XX:+UseParNewGC
    年老代用-XX:+UseConcMarkSweepGC

3.你用过哪些性能调优工具?

1、jdk自带监控工具

  • jconsole,Java Monitoring and Management Console是从java5开始,在JDK中自带的java监控和管理控制台,用于对JVM中内存,线程和类等的监控
  • jvisualvm,jdk自带全能工具,可以分析内存快照、线程快照;监控内存变化、GC变化等。

2、第三方

  • MAT,Memory Analyzer Tool,一个基于Eclipse的内存分析工具,是一个快速、功能丰富的Javaheap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗
  • GChisto,一款专业分析gc日志的工具
  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dream_sky分享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值