• 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html
  • 极客专栏正式上线!欢迎访问 https://www.jikewenku.com/topic.html

JVM面试问题总结

极客笔记 Geekerstar 8个月前 (08-10) 381次浏览 已收录 0个评论 扫描二维码
文章目录[隐藏]

1. 讲一下Java内存划分

Java虚拟机在运行程序时会把其自动管理的内存划分为以下几个区域:

– 堆内存:所有线程共享,对象实例。当扩展内存大于可用内存,抛OOM。

– 方法区:已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。当内存申请大于实际可用内存,抛OOM。(JDK1.8以前,1.8已经移到本地内存)

– 程序计数器:是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。是Java虚拟机规范中唯一没有规定OOM(OutOfMemoryError)的区域。

Java虚拟机栈:也是线程私有的,它的生命周期与线程相同。执行java方法。若线程请求深度大于栈的深度,抛StackOverflowError。若栈在动态扩展时无法请求足够内存,抛OOM。

– 本地方法栈:与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。也会抛StackOverflowError和OOM。

JMM会对每个线程分配一个区域(包括程序计数器、虚拟机栈、本地方法栈)用于存储线程私有的数据。其余数据存储在 JVM堆 及 方法区。

堆内存里面分为老年代和新生代,其中新生代中分为 Eden 区,from survivor 区和 to survivor 区

2. 有哪些垃圾收集算法

引用计数法(无法解决循环引用的问题,不被java采纳)

根搜索算法

现代虚拟机中的垃圾搜集算法:

  • 标记-清除
  • 复制算法(新生代)
  • 标记-压缩(老年代)

分代收集法

3. 哪些对象可以作为GC Roots?

虚拟机栈(栈帧中的本地变量表)中的引用的对象

方法区中的类静态属性引用的对象

方法区中的常量引用的对象

本地方法栈中JNI(Native方法)的引用对象

4. GC是在什么时候,对什么东西,做了什么事情?

什么时候

Minor GC触发条件:当Eden区满时,触发Minor GC。

Full GC触发条件:

(1)调用System.gc时,系统建议执行Full GC,但是不必然执行

(2)老年代空间不足

(3)方法区空间不足(JDK 1.8之前,已经移到本地内存)

(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存

(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

什么东西

从gc root搜索不到,而且经过第一次标记、清理后,仍然没有复活的对象。

做了什么

最浅显的理解为释放对象。但是从 GC 的底层机制可以看出,对于可以搜索到的对象是进行复制操作,对于搜索不到的对象,调用finalize()方法进行释放。

具体过程:当GC线程启动时,会通过可达性分析法把 Eden 区和 From survivor 区的存活对象复制到 To survivor 区,然后把 Eden survivor 和From survivor 区的对象释放掉。当 GC 轮循扫描 To survivor 区一定次数后,把依然存活的对象复制到老年代,然后释放 To survivor 区的对象。

对于用可达性分析法搜索不到的对象,GC并不一定会回收该对象。要完全回收一个对象,至少需要经过两次标记的过程。

第一次标记:对于一个没有其他引用的对象,筛选该对象是否有必要执行finalize()方法,如果没有执行必要,则意味可直接回收。(筛选依据:是否复写或执行过finalize()方法;因为finalize方法只能被执行一次)。

第二次标记:如果被筛选判定位有必要执行,则会放入FQueue队列,并自动创建一个低优先级的finalize线程来执行释放操作。如果在一个对象释放前被其他对象引用,则该对象会被移除FQueue队列。

5. 为什么要分两个 Survivor?

之所以要分两个 Survivor,而不是直接从 Survivor 直接移到 老年代区域,原因是老年代区域内的对象都是经过若干次 GC 过程之后存活下来的对象,并不是每一次 GC 存活下来的对象都需要移动到老年代区域内的,所以需要 from Survivor 区和 to Survivor区来保证 新生代 内存中的复制算法的实行,提高清除效率。

6. JVM 的 happens-before 原则是什么?

1. 程序顺序原则:一个线程内必须保证语义串行性,按照代码顺序执行

2. 锁规则:解锁(unlock)操作必然发生在后续的同一个锁的加锁(lock)之前

3. volatile规则:volatile变量的写,先发生于读

4. 线程启动规则:线程的start()方法先于它的每一个动作

5. 传递性:A先于B ,B先于C 那么A必然先于C

6. 线程终止规则:线程的所有操作先于线程的终结对线程 线程中断规则:interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生

7. 对象终结规则:对象的构造函数执行,结束先于finalize()方法

7. 讲到JMM应该还会提到对应的原子性、有序性、可见性以及volatile关键字

就请去多线程那边看吧!

8. GC 收集器

GC的收集器(重点是CMS和G1)

收集器这里我局的分类比较好记忆:

年轻代:

1. Serial 收集器

2. ParNew 收集器

3. Parallel Scavenge 收集器

老年代:

1. Serial Old 收集器

2. Parallel Old 收集器

3. CMS 收集器

特殊:G1 收集器(都回收~)

CMS 收集器

CMS(Concurrent Mark Sweep):Mark Sweep 指的是标记 – 清除算法。特点是并发收集、低停顿。

– 初始标记:仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿。

– 并发标记:进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿。

– 重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿。

– 并发清除:不需要停顿。

特点:在整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,不需要进行停顿。

– 吞吐量低:低停顿时间是以牺牲吞吐量为代价的,导致 CPU 利用率不够高。

– 无法处理浮动垃圾,可能出现 Concurrent Mode Failure。浮动垃圾是指并发清除阶段由于用户线程继续运行而产生的垃圾,这部分垃圾只能到下一次 GC 时才能进行回收。由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure,这时虚拟机将临时启用 Serial Old 来替代 CMS。

– 标记 – 清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前触发一次 Full GC。

G1 收集器

面向服务端应用G1 可以直接对新生代和老年代一起回收。

G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。

通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。

每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的被谁引用。通过使用 Remembered Set,在做可达性分析的时候就可以避免全堆扫描。

– 初始标记

– 并发标记

– 最终标记:为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 里面,最终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中。这阶段需要停顿线程,但是可并行执行。

– 筛选回收:首先对各个 Region 中的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。

主要特点是:整体来看是基于“标记 – 整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“复制”算法实现的。这样不会出现内存空间碎片。
并且实现可预测的停顿。

参考资料

1. JVM(2):JVM内存结构

2. GC详解及Minor GC和Full GC触发条件总结

3. Java Hotspot G1 GC的一些关键技术


丨极客文库, 版权所有丨如未注明 , 均为原创丨
本网站采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行授权
转载请注明原文链接:JVM面试问题总结
喜欢 (0)
[247507792@qq.com]
分享 (0)
Geekerstar
关于作者:
本站技术支持

您必须 登录 才能发表评论!

  • 精品技术教程
  • 编程资源分享
  • 问答交流社区
  • 极客文库知识库

客服QQ


QQ:2248886839


工作时间:09:00-23:00