JVM面试问题

76 阅读4分钟

1.什么情况下会发生栈内存溢出?

栈空间设置比较小,方法递归的深度大,那么就有可能出现栈内存溢出

2.JVM的内存结构,Eden和Survivor比例?

Eden:S0:S1 = 8 : 1 : 1

3.JVM内存为什么要分为新生代、老年代、持久代。新生代中为什么要分为Eden和Survivor

根据对象存活的时长来存放不同的内存区域。新生代和老年代的对象存活时长是不一样的,对于新生代的对象,它需要频繁的gc,而老年代的对象gc比较少。这样区分开来,对于不同的内存区域可以使用不同的gc算法。新生代中又分为Eden和Survivor是因为在工程应用中的统计分析,大部分的对象都是朝生夕死的,一个minor GC能够存活下来的对象是比较少的,比较适合标记-复制算法进行gc, 性能比较好。

4.JVM中一次完整的GC流程是怎么样的,对象如何晋升到老年代?

  1. 新创建的对象放入新生代的Eden区,如果对象比较大,直接进入老年代
  2. Eden区不够,进行minor GC, 这时可使用的空间够了,则放入Eden
  3. minor GC 存活下来的对象,直接进入survivor区
  4. 对象经历多次minor GC还能存活,则进入老年代;每GC一次,对象年龄加1,达到阈值进入老年代,阈值一般设置为15
  5. 老年代不够,进行full GC

5.说说你知道的几种主要的JVM参数

  • Xms=20M -- 设置堆初始大小
  • Xmx=20M -- 设置堆最大大小
  • Xmn=10M -- 设置新生代大小
  • Xss=1M -- 设置栈大小
  • XX:MaxTenuringThreshold=15 -- 设置老年代的阈值

6.你知道哪几种垃圾收集器?各自的有缺点

CMS(Current Mark Sweep)

它所使用的是标记-清除算法 优点是: 并发处理的,用户线程暂停时间少,在清理过程中,用户线程和GC线程是共存的,低停顿 缺点是: 并发处理比较占CPU资源,如果机器配置不够,虽然用户线程可以共存,但是处理时间减少了,相应地可能响应变慢。此外,它是基于标记-清除算法来收集内存的,这个算法有明显的特点就是带来内存碎片化问题,如果这个时候有大对象要分配,实际可用的内存可能足够,但是都是分散的,这个时候就会触发full GC

G1(Garbage First)

使用标记-整理算法,内存碎片化问题可以得到解决,可以缩短stop-the-world的时间,但是在垃圾回收时,相比于CMS收集器,它占用的负载要大

7.垃圾回收算法的实现原理

这个问题有点奇怪,回收算法哪来的原理,算法就是算法,回收就是一个可实现的思路。具体如下:

  • 是不是垃圾?(如何将对象识别为垃圾)

判断对象是垃圾的标准是是否存在一条链路到达GC root,如果有,则对象是存活的,否在,对象是垃圾,应该被回收。

  • 如何回收(采用什么样的算法回收)

回收算法有很多,比如标记-清除算法,标记-整理算法,复制算法等。各个算法有其自身的特点,比如标记-清除算法,它是一种比较常用的基础算法,但是会带来内存碎片化的问题,后续提出的标记-整理算法,在其基础上可以移动对象的位置,整理内存空间,解决内存碎片化的问题,但是在移动对象的过程中会暂停用户线程,叫stop-the-world。再比如复制算法,它的出现要解决大量需要回收对象的问题,比如新生代中,对象都是朝生夕死的,每次都标记-清除,不如直接复制来得快,效率高,所以这种算法就比较适合用在新生代中。此外,有些垃圾回收器的实现,不是固定的使用某一种算法,而是根据自身的需要,采用比较合适的算法,甚至在其基础上进行一些改进。

8.当出现内存溢出,该如何排查

  • 先获取到应用程序的dump文件
  • 再使用工具分析文件中的大对象是什么
  • 大对象产生的原因
  • 尝试优化代码,减少大对象
  • 如果不能优化掉大对象,那么需要从提高硬件水平,提高内存空间,再线上观察。