常见面试题及进阶知识点详解

1.2面试常见问题及解析

1.2.1 请谈谈你对JVM内存模型的理解

问题剖析:当面试官提出这个问题时,就是想考察你对JVM核心基础的理解。这个问题看似容易回答,但是准备不足则难以给出较为满意的答案。可能很多同学的答案回答仅仅是流水账式的列出相关知识点,而没有系统性地组织语言将各个知识点串起来。下面先给出回答这个问题相关的知识点,然后给出一个回答该问题的示例模板。
图片说明

上图展示了JVM中内存模型,不难看出线程内驱动程序运行的程序计数器、虚拟机栈和本地方法栈都要占用内存;而堆和方法区则是独立于线程占用内存。从内存区域是否共享这个维度作为划分手段,线程内部占用的内存区域为私有,不同线程之间不可互相访问;而堆、方法区和直接内存则是公共且可以互相访问。

回答模板:首先介绍JVM内存模型是什么?随后介绍JVM内存模型存在的意义,与JVM中其他知识点(例如GC)的关联;随后逐条介绍程序计数器、虚拟机栈、本地方法栈、堆、方法区、运行时常量池和直接内存;随后从私有和共享的角度对上述提及的内存区域进行区分。如果面试官中途对某一个点进行深入,可以结合1.1章中各节知识点进行介绍,重点谈谈自己的理解,而不是背诵。

1.2.2 请谈谈你对JVM堆的理解

问题剖析:当面试官提出这个问题时,就是想考察你对JVM中核心部分堆的理解,因为堆上经常发生GC,在线上中出现FullGC是很常见的事情,因此不仅要会Dump堆的实际使用情况,还要堆的内存结构有较深的理解。除此之外,随着Java版本的发展,堆内存的结构也出现了不小的变化,因此回答不应仅仅局限于老版本的堆内存结构,还要与时俱进地分析版本之间的差异性。

在JDK7及其更老的版本中,堆通常被分为新生代老生代以及永生代。JDK8之后方法区(HotSpot 的永久代)被彻底移除了(JDK1.7就已经开始了),取而代之是元空间,元空间使用的是直接内存。

回答模板:首先介绍堆是用来做什么的?都哪些内容存在堆上?堆与JVM中其他知识点(例如GC)的关联;随后结合JDK版本对堆内存结构的差异性进行阐述;最后还要对1.2.3中的问题进行阐述。

1.2.3 JVM堆内存大小一般如何分配

问题阐述:当面试官提出这个问题时,就是想考察你是否对堆有很深的理解。堆总体大小以及各个区域大小的分配在很大程度上会关联到GC效率。

回答模板:在JDK8中新生代约占整个堆1/3的空间(Eden:from:to = 8:1:1),其他2/3的空间分配给老年代;随后结合Eden,from和to的比例谈谈新生代GC算法的运行过程;最后再结合JVM调优谈谈哪些关于堆的参数修改将有利于提高JVM性能。

1.2.4* 请谈谈方法区和永生代的区别

问题阐述:当面试官提出这个问题时,就是想考察你对方法区的认识,因为很多人认为方法区和永生代同一个东西,但是二者在狭义上还是有一些区别,不能简单地混为一谈。

方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。也就是说,永久代是HotSpot的概念,方法区是Java虚拟机规范中的定义,是一种规范,而永久代是一种实现,一个是标准一个是实现,其他的虚拟机实现并没有永久代这一说法。此外,不同版本的JVM对永生代的支持程度也不同,例如将JRockit中的Java Mission Control迁移至HotSpot时就出现了因方法区差异导致的迁移困难问题。而以元数据空间这种使用本地内存的方式则有利于JVM间不同版本迁移的实现。这里如果读者对JVM的理解足够深,可以展开聊聊不同JVM间在方法区设计实现的异同。

1.3进阶知识点与思考

1.3.1 区分JVM内存模型和Java内存模型

JVM内存模型描述了Java虚拟机如何分配及使用内存;而Java内存模型(JMM)则定义了线程和主内存之间的抽象关系,即JMM定义了JVM在计算机内存(RAM)中的工作方式。Java内存模型更多地就多线程场景下内存中的一致性问题进行探讨(重点是因为内存共享而产生的读写问题),而不关心内存在使用上的设计与管理。限于篇幅与主题,这里不再详细展开介绍Java内存模型,感兴趣的同学可以自己阅读Java并发编程艺术学习。

1.3.2 区分JVM程序计数器在执行指令上与OS层面的区别

无论是操作系统层面还是JVM层面,机器在执行时都会将代码转化成指令(也可以理解为机器码),这种指令一般不容易理解,但是执行效率极高。在OS中的指令一般带有操作数,而JVM的指令不带有操作数,下面以加法为例简要展示二者的差异(OS指令仅参考一种指令设计模式,且操作码和操作数地址均为举例)。

图片说明

执行一条加法操作时,对应的命令无论是JVM还是OS至少需要以下内容:

  • 操作码
  • 操作数1
  • 操作数2

在JVM中,操作码与操作数逻辑上并不一起。操作码单独存放,所有操作数则存放于操作数栈中。操作数栈与数据结构中的“栈”一样,具有后进先出的特性。当构建一条指令时,根据操作码的要求从栈中弹出指定数量的操作数送进CPU寄存器中用于运算。以加法为例,从操作数栈中弹出e和d,然后和操作码一起送入CPU进行运算。当运算完成后将结果压入操作数栈。而OS中的指令与操作数绑定在一起,还可能会附加运算结果存放的地址与下一条指令的地址。如果想详细了解OS中指令的种类和执行过程,可以参考一些计算机操作系统以及计算机组成原理的书籍,本文在这里不做赘述,感兴趣的同学可以自己扩展学习。

1.3.3 逃逸分析

逃逸分析是一项JVM优化技术,用于虚拟机分析对象的作用域。在面试中与这个知识点关联度最大的问题就是”所有对象都在堆空间上分配内存么?“。首先给出这个问题的答案,是否定的,并非所有对象都在堆空间分配内存。下面首先介绍一下逃逸分析,然后从理论上详细解答这个问题,最后给出逃逸分析中的其他几项技术。

Java运行需要经过两个必要的阶段,首先基于javac命令将.java文件编译为.class;然后JVM将字节码转化为机器可执行的指令,转化时逐条读入逐条翻译。这种转化过程一般执行效率较差,为了优化这个问题提出了即时编译技术(JIT)。引入JIT后,JVM具有一定智能性,当JVM发现某一段方法或代码块执行的非常频繁时,就会认为出现了热点代码。为了避免频繁将这段代码转化为机器指令,JIT会将这部分热点代码翻译后放到缓存里以供调用。JIT在判定逃逸时也有较大作用。逃逸是指在方法A内被创建的对象不仅在本方法内被引用,对于其他方法而言也能获得其引用。如果对象发生了逃逸,会产生如下影响:

  • 方法A创建的对象在方法结束时依旧存在引用,因此改对象无法被GC回收
  • 方法A尚未结束时,方法B修改了

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试必问JVM考点精讲 文章被收录于专栏

“挨踢”行业行情日益严峻,企业招聘的门槛也随之越来越高,大厂hc少之又少。 庞大的知识体系下,不知道学什么、怎么学? 面试高频考点是什么、怎么回答才能得到面试官的青睐? 作为后端求职者,在Java的道路上越走越宽。 本专刊则针对Java面试考点上,精讲JVM知识点,为大家的大厂求职路保驾护航! 针对如今校招痛点,深入详解JVM知识考点,列出高频真题并详细解答!探索JVM精髓!

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务