0
点赞
收藏
分享

微信扫一扫

被问烂了的JVM,又引发了一场血雨腥风的“垃圾”面试。。。

愚鱼看书说故事 2022-04-02 阅读 63
java

金三银四这波招聘热潮到末尾了,这几天一直在忙着新人的培训,偶尔也有一些面试给到我,同时也好久没有给大家分享面试的经验了,刚好我们最近在招聘偏运维的开发,有对JVM部分的知识要求,顺带拎了一个记忆比较深刻的面试给到大家,一起看看这个小哥的水平如何(省略掉了其他的部分,只留下了JVM问题部分的面试)

         

依旧先给大家看看面试知识点

  • 说一下 JVM 的主要组成部分及其作用?

  • 简单说一下 JVM 运行时数据区吧

  • 简单谈一些深拷贝和浅拷贝

  • Minor GC和Full GC 有什么不同呢

  • 如何判断对象可以被回收

  • 解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法

面试正式开始了:

       

       

。。。。。省略掉没有肉的自我介绍和简单的互相了解

面试问答部分

我:说一下 JVM 的主要组成部分及其作用?

答:

JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。

  • Class loader(类装载):根据给定的全限定名类名(如:java.lang.Object)来装载class文件到Runtime data area中的method area。

  • Execution engine(执行引擎):执行classes中的指令。

  • Native Interface(本地接口):与native libraries交互,是其它编程语言交互的接口。

  • Runtime data area(运行时数据区域):这就是我们常说的JVM的内存。

作用 :首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。

我: 简单说一下 JVM 运行时数据区吧

答:

Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存区域划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有些区域随着虚拟机进程的启动而存在,有些区域则是依赖线程的启动和结束而建立和销毁。Java 虚拟机所管理的内存被划分为:

  • 程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成;

  • Java 虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作数栈、动态链接、方法出口等信息;

  • 本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;

  • Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存;

  • 方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。

我:简单谈一些深拷贝和浅拷贝

答:

  • 浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,

  • 深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,

  • 使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。

  • 浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。

  • 深复制:在计算机中开辟一块新的内存地址用于存放复制的对象。

我:Minor GC和Full GC 有什么不同呢

答:

Minor GC/Young GC:指发生新生代的的垃圾收集动作,Minor

GC非常频繁,回收速度一般也比较快。

Major GC/Full GC:一般会回收老年代,年轻代,方法区的垃圾,

Major GC的速度一般会比Minor GC的慢10倍以上

我:如何判断对象可以被回收

答:

堆中几乎放着所有的对象实例,对堆垃圾回收前的第一步就是要判断哪些对象已

经死亡 一般常用的算法有 GC root和 可达性分析

我:解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法

答:

通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间;而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor(又可分为From Survivor和To Survivor)、Tenured;方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据;程序中的字面量(literal)如直接书写的100、”hello”和常量都是放在常量池中,常量池是方法区的一部分,。栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,栈和堆的大小都可以通过JVM的启动参数来进行调整,栈空间用光了会引发StackOverflowError,而堆和常量池空间不足则会引发OutOfMemoryError。

我:能大概说下对象分配规则

答:

  • 对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。

  • 大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。

  • 长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。

  • 动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。

  • 空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。

我:如果线上项目突然出现oom异常你会怎么做?

答:

线上故障主要会包括 CPU、磁盘、内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍。

同时例如 jstack、jmap 等工具也是不囿于一个方面的问题的,基本上出问题就是 df、free、top 三连,然后依次 jstack、jmap 伺候,具体问题具体分析即可。

我:为什么 G1 不维护年轻代到老年代的记忆集?

答:

G1 分了 young GC 和 mixed GC。

young GC 会选取所有年轻代的 region 进行收集。

midex GC 会选取所有年轻代的 region 和一些收集收益高的老年代 region 进行收集。

所以年轻代的 region 都在收集范围内,所以不需要额外记录年轻代到老年代的跨代引用

答完这些我就问了点其他的知识,从上面的一些问题可以看出他的JVM知识是非常扎实的,能够应对一些常见的问题和稍微棘手一些问题 ,有些小伙伴可能觉得我问的 “很简单” 其实不然 ,从这些点 能够看出他的知识还是很扎实的。我随机提一个点的知识他都能够很好的去应对。

看完他的面试,你觉得自己面试的话能够如此顺滑么?

我整理了一份大厂面试资料,拉到尾部扫码领取哦

 

举报

相关推荐

0 条评论