2023年面试篇【JVM面试技巧篇01】

事先声明,基于原理图所做的面试拆解技巧篇,如有雷同,那就见了鬼了~,另外,欢迎意见和批评,嘴炮,请绕道咯~




其次呢,推荐我觉得不错的技术大佬文章,也希望可以帮助到很多的小伙伴们~~

 本文到此结束~~

开玩笑了,活跃下轻松愉悦的气氛嘛,此时可能会好奇我到底分享那几位呢,别急,别急,主要是现在技术的获取途径太广了,可以看csdn、简书、牛客网、力扣等等,都是图文并茂的,如果遇到比较好的文章,还可以通过关注公众号,每天一篇文章分享,如果这些图文并茂的不喜欢,没关系,我们还有B站、慕课网等网络视频,图文并茂+免费人工讲解篇,如果还不能满足您的胃口,更别急,我们还有图灵、尚硅谷、黑马、马士兵、鲁班等培训课堂的专业讲师人的公开课视频资源,只能说讲课我们都是专业滴,哈哈,如果还不能满足您的话,我们讲师团队还有各种VIP服务,不要998、不要668,588请您带回家,怎么样,各位看官,您想选择那种呢?

不是我不想分享一些原理篇,主要是技术原理篇种类繁多,有轮子了,我为什么要造呢,我搬过来不行嘛,哈哈,既然要搬过来,肯定要找最好的,那么找一篇好的技术文章就需要我们碰运气了,为什么说需要碰运气,是因为现在技术人员的水平参差不齐,分享的水平也有深浅,如果正好碰到了一个技术文章正适合我现在需要的版本,那么恭喜你,你的运气占了50%,剩下的50%,只能看你实践过程中有没有遇到其他的问题了,当然了,这只是我片面之词,如有不对的地方,还望各位大佬点评指正,在此先谢过各位看官。


感谢各位看官可以看到这里,那就系好安全带,发车了~

正文篇:

面试官:jvm有没有了解过呢?简单说一下?

候选人心里:我C,简单说一下?你这叫简单说一下吗?我怎么跟你说,jvm这么大,我从何说起?老哥你想坑我吗?还是想让我自己挖坑自己跳呢?你给个痛快得了~
讲解:遇到这种开放题,心里很捉急,但你却什么也做不了,只能默默承受着,这范围也忒广了点,那么我们怎么回复呢?

一、特性

  •  跨平台性 
  • JVM的语言无关性
  • 可以理解为代码 -----> 系统执行的中间层,抹平语言的差异性,抹平OS的差异性

二、常见JVM实现

 三、大致体系

扫描二维码关注公众号,回复: 14768479 查看本文章

四、 运行时数据区(重点)

五、各个区域的职责(重点)

六、类加载

 

加载的时机

什么是需要开始类第一个阶段“加载”,虚拟机规范没有强制约束,这点交给虚拟机的具体实现来自由把控。
JVM 虚拟机的实现都是使用的懒加载,就是什么时候需要这个类了我才去加载,并不是说一个 jar 文件里面有 200 多个类,但实际我只用到了其中的一个
类,我不需要把 200 多个类全部加载进来。(如果你自己写一个 JVM 倒是可以这么干!)
“加载 loading ”阶段是整个类加载(class loading)过程的一个阶段。
加载阶段虚拟机需要完成以下 3 件事情:
        1)通过一个类的全限定名来获取定义此类的二进制字节流。
        2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
        3)在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。
 

验证(总结)

验证阶段对于虚拟机的类加载机制来说,是一个非常重要的、 但却不是必须要执行的阶段,因为验证阶段只有通过或者不通过的差别,只要通过了验证, 其后就对程序运行期没有任何影响了。如果程序运行的全部代码( 包括自己编写的、第三方包中的、从外部加载的、动态生成的等所有代码 ) 都已经被反复使用和验证过,在生产环境的实施阶段就可以考虑使用-Xverify:none 参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

准备

准备阶段是正式为类中定义的变量(被 static 修饰的变量)分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。 这个阶段中有两个容易产生混淆的概念需要强调一下:
首先,这时候进行内存分配的仅包括类变量(被 static 修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在 Java 堆中。 其次,这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为: public static int value=123; 那变量 value 在准备阶段过后的初始值为 0 而不是 123 ,因为这时候尚未开始执行任何 Java 方法,而把 value 赋值为 123 是后续的初始化环节。
 

解析

解析阶段是 JVM 将常量池内的符号引用替换为直接引用的过程。
符号引用是一种定义,可以是任何字面上的含义,而直接引用就是直接指向目标的指针、相对偏移量。 直接引用的对象都存在于内存中,你可以把通讯录里的女友手机号码,类比为符号引用,把面对面和你吃饭的女朋友,类比为直接引用。
解析大体可以分为:
  1. 类或接口的解析
  2. 字段解析
  3. 类方法解析
  4. 接口方法解析
我们了解几个经常发生的异常,就与这个阶段有关。
java.lang.NoSuchFieldError 根据继承关系从下往上,找不到相关字段时的报错。(字段解析异常)
java.lang.IllegalAccessError 字段或者方法,访问权限不具备时的错误。(类或接口的解析异常)
java.lang.NoSuchMethodError 找不到相关方法时的错误。(类方法解析、接口方法解析时发生的异常)

初始化

初始化主要是对一个 class 中的 static{} 语句进行操作(对应字节码就是 clinit 方法)。 <clinit >()方法对于类或接口来说并不是必需的,如果一个类中没有静态语句块,也没有对变量的赋值操作,那么编译器可以不为这个类生成< clinit >()方法。 初始化阶段,虚拟机规范则是严格规定了有且只有 6 种情况必须立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始):
1 )遇到 new getstatic putstatic invokestatic 4 条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这 4 条指令的最常见的
Java 代码场景是:
  1. 使用 new 关键字实例化对象的时候。
  2. 读取或设置一个类的静态字段(被 final 修饰、已在编译期把结果放入常量池的静态字段除外)的时候
  3.  调用一个类的静态方法的时候。
2 )使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
3 )当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
4 )当虚拟机启动时,用户需要指定一个要执行的主类(包含 main ()方法的那个类),虚拟机会先初始化这个主类。
5 )当使用 JDK 1.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果 REF_getStatic REF_putStatic REF_invokeStatic 的方法
句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。
6 )当一个接口中定义了 JDK1.8 新加入的默认方法(被 default 关键字修饰的接口方法)时,如果这个接口的实现类发生了初始化,那该接口要在其之前被初始化。

类加载器

好处: Java 类随着它的类加载器一起具备了一种带有优先级的层次关系,保障了核心API的安全。

弊端:单向加载,如果有核心类访问应用类,此时就满足不了啦,但这种情况很少出现。

讲到这边的话,就不得不提下tomcat的类加载,打破了双亲委派,但是顶层的核心类和接口,还是一份的。

总结:

1、jvm的特性是 跨平台、跨语言的。

2、常见的jvm有Jrocket,J9,TaobaoVM,LiquidVM,zing,Hotspot,除了Hotspot其他了解即可。

3、JVM的知识体系,包括类文件结构、类加载、垃圾回收、执行引擎、JVM自身优化技术(逃逸分析、方法内联)、内存结构(重点)

4、运行时数据区域,耳熟能详的,看下图,我就不写了,此时不需要介绍具体哪块存哪些东西,等他提问。

5、类加载机制,加载、验证、准备、解析、初始化、使用、卸载,也不需要介绍具体内容,可能引发tomcat打破双亲委派,为什么打破,打破有什么好处,不打破有什么弊端?

6、垃圾回收机制,垃圾回收算法。

7、判断对象的存活,可达性分析和引用计数法,GCRoot包括哪些,可以简单提一下。此时可能会引发G1使用的三色标记,为什么弃用了之前的算法采用三色标记。

8、垃圾回收器,各个垃圾回收器的标记过程与使用场景。

 ------------------------------------------------ 我是华丽分割线---------------------------------------------------------

垃圾回收器是一大类,下次分享细节咯,其实到上面就差不多了,你需要自己总结下自己的语言表达出来,我不写答案的原因是想让各位自己动手查、自己动手记笔记会很深刻,记忆的时间会很长,并且稍微点破一下,立马能想起来,而不是面试官问到了就问到了,我回去稍微看一下,也不做review,下次问到还是不会,没有任何意义, 在此次回答的之后,你可能还会遇到其他的几个问题,

比如: 安全点和安全区域是什么?

G1与其他垃圾回收器最大的不同是什么?

Rset与CardTable是干嘛使的?

三色标记的大致流程可以讲一下吗?

各个类加载机制步骤做了什么操作?

运行时数据区域内都存储了什么?

JDK1.8为什么使用元空间代替了永久代?

方法区、永久代、元空间之间有什么关系?

为什么会有直接内存呢,跟垃圾回收有什么关联,使用它有什么好处?

这些问题的答案很多,也很杂,不是简简单单看一篇博客就能记住的,即使当时记住了,一问一些为什么这么做,为什么这么设计,心里还是没有谱,那我觉得这个知识点和花的这个时间是不值得的,所以希望各位看官可以总结自己的一套理论知识,形成自己的体系,如果有不会的可以发到星球,有大佬们解答的,安咯,在此希望可以看到各位小伙伴动手能力啦,希望可以有一点帮助哟,各位看官晚安咯,有问题可以评论哈,分享的大佬们,还在整理中,稍安勿躁哦,各位看官,如果觉得还可以,希望点赞+关注咯。

猜你喜欢

转载自blog.csdn.net/weixin_42080277/article/details/129567747