JVM(面试问题简析)学习笔记

文章目录

  • 1. JVM中有哪几块内存区域?Java 8 之后对内存分代做了什么改进?
  • 2. 你知道JVM是如何运行起来的吗?堆内存中对象的分配的基本策略?
  • 3. 说说 JVM 在哪些情况下会触发垃圾回收?JVM 的年轻代垃圾回收算法?
  • 4. 说说对象什么时候转移到老年代,以及老年代垃圾回收算法
  • 5. 常用的垃圾回收器有什么?
  • 6. 生产环境中的 Tomcat 是如何设置 JVM 参数的?如何检测 JVM 运行情况?
  • 7. 发生 OOM 之后,应该如何排查和处理线上系统的 OOM 问题?

1. JVM中有哪几块内存区域?Java 8 之后对内存分代做了什么改进?

  • Java 8 之前:
    JVM(面试问题简析)学习笔记_第1张图片

    • 上图是 JVM 中最基本的、也是最常用的三个内存区域
    • 程序运行后,常量池和所有类信息都会加载到永久代内,Spring 实例化的所有对象都会加载到堆内存中,当执行请求时需要由线程进行执行所以栈内存就是线程独有的内存
  • Java 8 以后的内存分代进行的改进:

    • 常量池放入堆内存中
    • 类信息放入到元空间中

2. 你知道JVM是如何运行起来的吗?堆内存中对象的分配的基本策略?

  • 如果一个类中包含了一个 main 方法,当执行 main 方法时,会启动一个 JVM 的进程,它会默认一个 main 线程,这个main 线程就会负责执行一个 main 方法的方法,进而创建各种对象,实现逻辑
  • 如果把代码放到 tomcat 中,所有的类都会被类加载器加载到元空间中,Spring 容器启动后会扫描对应的代码,会通过反射技术,创建出类的 Bean 实例,并加载到堆内存中。
  • 当有请求进入 Tomcat 时,都会分配一个线程去处理它, 每一个线程都会分配一个栈内存。在处理请求时可能会使用到 Bean 实例中的方法,执行方法时会在栈内存中会创建一个栈帧,并且把该方法中的局部变量存在栈帧中。当需要使用到局部的对象的时候会在堆内存中创建对象实例,接着栈帧中的局部变量会去引用堆内存中的对象实例。在执行当前方法的过程中引用到其他方法,则会将该方法压入栈顶。当方法执行完毕后会依次出栈,并将局部变量销毁
    JVM(面试问题简析)学习笔记_第2张图片

3. 说说 JVM 在哪些情况下会触发垃圾回收?JVM 的年轻代垃圾回收算法?

  • 堆内存中的内存分代
    JVM(面试问题简析)学习笔记_第3张图片

    • eden、s0,s1 都属于新生代
    • tentired 属于老年代
    • 新生代中内存分配规则一般为 8:1:1
  • 如果eden区满了,就会触发年轻代的GC

  • 在执行年轻代GC的时候,会将没有任何引用的对象回收,一般情况下被方法的局部变量、类的静态变量引用的对象不会被回收,其他都会被回收

  • 一般,再垃圾回收处理时,一边判断哪些没有被引用,一边进行回收是不现实的,所以有一个 stop the world 的概念,也就是在垃圾回收时,会停止工作线程运行,然后再判断哪些可以回收

  • 年轻代垃圾回收的算法

    • 复制算法
    • 当 eden 区满了之后,会将 eden 区中还有被引用的对象,复制到 s0 区,然后将 eden 区整个清空
    • 当 eden 区再一次满了之后,会将 eden + s0 区中还有被引用的对象复制到 s1 区域,然后将 eden + s0 区域整个清空
    • 在下一次就是,将 eden + s1 区域还有被引用的对象复制到 s0,将 eden + s1 区域整个清空
      以此往复……

4. 说说对象什么时候转移到老年代,以及老年代垃圾回收算法

  • 以下三种情况会转移到老年代

    1. 在 s0、s1 来回复制很多次(一般15次)的对象,也即熬过很多次垃圾回收,长期存活的对象
    2. 很大的对象
    3. 回收时所有存活的对象比 s 区域内存还要大,不能直接存入 s 区域的对象
  • 对于老年代而言,其中的垃圾对象不是很多,大部分都是需要长期存活的对象

  • 老年代的垃圾回收比年轻代的速度会慢 10 倍以上

  • 所以老年代的垃圾回收算法主要为:

    • 标记-清理
      • 标记出没有被引用的垃圾对象,直接清理掉
      • 这种方式会引发内存碎片的问题
    • 标记-整理
      • 将老年代中存活的对象标记出来,并将它们压缩整理到一块连续的内存空间内,这样剩余的可用空间也就是连续的
      • 这样就可以解决上面方法产生的问题

5. 常用的垃圾回收器有什么?

  • 比较常用的为以下三种
  1. parnew + cms 的组合

    • 在 JDK 8 及 8 以前较为常用
    • parnew 是针对年轻代,和上文的算法大致相同,只不过是使用多线程进行回收
    • cms 是针对老年代,它会将老年代的回收分为好几个阶段:初始标记、并发标记、并发清理……
    • 使用这种方法进行垃圾回收,尽可能的让垃圾回收和工作线程并发进行,尽量减少 stop the world 的时长
  2. g1 直接分代回收

    • JDK 9 及以后主推
    • 年轻代、老年代都适用

6. 生产环境中的 Tomcat 是如何设置 JVM 参数的?如何检测 JVM 运行情况?

  • 如果通过预估+压测,做一份生产环境的 JVM 参数出来,如何区观察 JVM 运行的情况

7. 发生 OOM 之后,应该如何排查和处理线上系统的 OOM 问题?

你可能感兴趣的:(JVM,面试,jvm,面试,学习)