JVM面试题常见概念总结

1.介绍一下JVM的内存模型

  • 线程私有的,有虚拟机栈,本地方法栈,程序计数器
  • 线程共享的,有堆和方法区

程序计数器

看作是当前线程执行的字节码行号的一个指示器,指示下一个要执行的语句,所以必须是线程私有的

虚拟机栈

就是线程的栈,保存局部变量。当执行一个方法时,会向这个栈区放入一个栈帧

本地方法栈

和虚拟机栈服务,区别就是虚拟机栈是为Java字节码服务;而本地方法栈是为本地native方法服务

方法区

用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

堆区(重点)

  1. 堆区分为新生区和老年区,默认占比是1:2,其中新生代包括Eden区,S1和S2区
  2. 采用分代回收算法(即每一代所用的垃圾收集算法都不一样)
    • 新生代使用复制算法+标记清除算法,新生代分为3个区,Eden区,S1,S2区,默认占比是8:1:1,当Eden区的空间用完时,JVM会发生minor GC
      • 把Eden区+S1区存活的对象放到S2区
      • 清空Eden区和S1区
      • From区和To区交换(指指针指向)
    • 每次From区和To区发生交换,对象的年龄+1,当年龄到达15,升级到老年区,对象过大的话也会直接创建到老年区
    • 老年区空间占比达到某个值的时候,会出发全局垃圾回收Full GC,一般使用标记清除算法。如果Full GC仍然无法进行对象的保存,会产生OOM异常

2.GC的算法

  1. 引用计数器
  2. 复制算法,优点快速,没有碎片;缺点是空间利用率不高,需要双倍的空间(S1区和S2区的存在)
  3. 标记清除算法,有空间碎片,但是不需要额外空间
    • GC ROOT遍历所有的GC ROOTs,把不可达的清除
  4. 标记整理算法,标记清除算法+整理

一定要清楚GC ROOT会暂停整个程序

3.Minor GC , Full GC的触发条件是什么?

  • Minor GC触发条件:

    当Eden区满的时候,触发Minor GC

  • Full GC的触发条件:

    • System.gc()方法的调用
    • 老年代空间不足
    • 通过Minor GC后进入老年代的平均大小大于老年代的可用内存
    • 由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

4.类加载的过程

加载—>连接—>初始化

连接又分为:验证,准备,解析

  • 验证
    确保加载的类信息符合JVM规范,没有安全方面的问题。

  • 准备
    正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。注意此时的设置初始值为默认值,具体赋值在初始化阶段完成。

  • 解析
    虚拟机常量池内的符号引用替换为直接引用(地址引用)的过程。

  • Java程序对类的使用方式可分为两种

    • 主动使用
    • 被动使用
  • 所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”才初始化他们

5.怎么表示一个对象是可回收的?

基本思路就是通过一系列名为”GCRoots”的对象作为起始点,从这个被称为GC Roots的对象开始向下搜索,如果一个对象到GCRoots没有任何引用链相连时,则说明此对象不可用。也即给定一个集合的引用作为根出发,通过引用关系遍历对象图,能被遍历到的(可到达的)对象就被判定为存活,没有被遍历到的就自然被判定为死亡。

可以作为GC ROOT的对象

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中JNI(即一般说的native方法)中引用的对象

6.类加载器,可以打破双亲委派么?

1)什么是类加载器?

类加载器 就是根据指定全限定名称将class文件加载到JVM内存,转为Class对象。

  • 启动类加载器(Bootstrap ClassLoader):由C++语言实现(针对HotSpot),负责将存放在<JAVA_HOME>\lib目录或-Xbootclasspath参数指定的路径中的类库加载到内存中。
  • 其他类加载器:由Java语言实现,继承自抽象类ClassLoader。如
    • 扩展类加载器(Extension ClassLoader):负责加载<JAVA_HOME>\lib\ext目录或java.ext.dirs系统变量指定的路径中的所有类库。
    • 应用程序类加载器(Application ClassLoader)。负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器。

2)双亲委派模型工作过程

如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。

3)为什么需要双亲委派模型?

在这里,先想一下,如果没有双亲委派,那么用户是不是可以自己定义一个java.lang.Object的同名类,java.lang.String的同名类,并把它放到ClassPath中,那么类之间的比较结果及类的唯一性将无法保证,因此,为什么需要双亲委派模型?防止内存中出现多份同样的字节码

4)怎么打破双亲委派模型?

打破双亲委派机制则不仅要继承ClassLoader类,还要重写loadClass和findClass方法。

7.垃圾收集器有哪些,及其原理

思路: 一定要记住典型的垃圾收集器,尤其是cms和G1,他们的原理和区别,设计的垃圾回收算法

1)几种垃圾收集器:

  • Serial收集器: 单线程的收集器,针对新生代,收集垃圾时,必须stop the world,使用复制算法
  • Serial Old收集器: 是Serial收集器的老年代版本,单线程收集器,使用标记整理算法
  • ParNew收集器: 是Serial的多线程版本
  • Parallel Scavenge收集器: 新生代收集器,复制算法的收集器,并发的多线程收集器,目标是达到一个可控的吞吐量,如果虚拟机总共运行100分钟,其中垃圾花掉1分钟,吞吐量就是99%。
  • Parallel Old收集器: 是Parallel Scavenge收集器的老年代版本,使用多线程,标记-整理算法
  • CMS(Concurrent Mark Sweep)收集器: 是一种以获得最短回收停顿时间为目标的收集器,标记清除算法,运行过程:初始标记,并发标记,重新标记,并发清除,收集结束会产生大量空间碎片。
  • G1收集器: 标记整理算法实现,运作流程主要包括以下:初始标记,并发标记,最终标记,筛选标记不会产生空间碎片,可以精确地控制停顿。

2)CMS收集器和G1收集器的区别

  • CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用;
  • G1收集器收集范围是老年代和新生代,不需要结合其他收集器使用;
  • CMS收集器以最小的停顿时间为目标的收集器;
  • G1收集器可预测垃圾回收的停顿时间
  • CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片
  • G1收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片

文章引用

常见的JVM面试题及答案整理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值