JVM面试总结

JVM面试总结

  1. 类加载机制

    • 装载

      全路径、类加载器、寻找类(双亲委派)、

    • 链接

      验证:文件格式验证、元数据验证、字节码验证、符号引用验证

      准备:为类的静态变量分配内存,并将其初始化为默认值,这是默认值的初始化,并不是赋值,需要注意

      解析:将类中的符号引用转换为直接引用(我的理解就是本来是通过变量引用,现在直接把空间地址传给它)

    • 初始化

      对类的成员变量,静态代码执行初始化操作

  2. 双亲委派模型

    往上找父,保证唯一

    • 2.1 类加载器类型:

      • BootStrap ClassLoader 启动类加载器、跟加载器
      • ExtClassLoader 扩展类加载器
      • AppClassLoader 应用类加载器
      • Customer ClassLoader 自定义类加载器
    • 2.2 作用

      • 保证JDK核心类的优先加载
    • 2.3 如何打破

      • 自定义类加载器,重写loadClass方法
      • 使用线程上下文类加载器
  3. 运行时数据区

    JVM运行时数据区,由此可引申到JMM内存模型

    • 内存划分:栈内存、堆内存、方法区、本地方法区、寄存器

    • JVM运行时数据区,方法区和堆内存

      堆内存又分为,老年代(Old – Major GC)、新生代(Young – Eden、Survivor(S0、S1))

      新生代:S0:S1 = 8:1:1

      S0和S1 存在的意义是 虽然浪费了10%的空间,但是避免了空间碎片

      当S0或S1存储不了大的对象的时候,存在一个内存担保机制,可以向Old借空间,用完了,再还给它

    • 垃圾回收算法

      • 标记删除
        • 空间碎片,内存不连续
        • 标记和清除都比较耗时,要扫描两次,效率比较低
        • Old
      • 标记复制
        • 浪费10%的空间
        • 空间连续
        • Young(Eden、S0、S1)
      • 标记整理
        • 没有保留区域
        • 没有空间碎片
        • Old

      Full GC = Major GC + Young GC+MetaSpace的GC

    • 垃圾回收器

      ​ 所有的垃圾回收期都有STW(Stop The World) 只是暂停时间长短不同而已

      ​ 吞吐量:用户业务代码执行的时间/(业务代码执行的时间+垃圾收集的时间)

      ​ 吞吐量越大,垃圾收集时间越短,用户代码就可以充分利用CPU资源

      jdk1.8默认使用Parallel GC

      jdk1.9默认使用G1

      • 串行收集器 单线程
        • Serial -> ParNew (多线程)
        • Serial Old
      • 并行收集器 吞吐量优先
        • Parallel Scanvenge
        • Parallel Old
      • 并发收集器 停顿时间优先
        • CMS
        • G1 jdk1.9之后是默认的
        • jdk11 还有一个ZGC(Z Garbage Collector) 停顿时间小于10ms
    • CMS:Concurrent Mark Sweep 并发类的垃圾收集器

      初始标记->并发标记->重新标记->并发清除

      标记清除 空间碎片

    • G1:Garbage-First Jdk1.9默认 再1.8中比较普遍

      垃圾优化,整体上属于标记整理算法,不会导致空间碎片

      Region区域,对堆重新进行了布局,逻辑存在Young、Old、Eden,物理上已经不是隔离的了

      初始标记->并发标记->最终标记->筛选回收->应用程序线程

      标记整理 减少空间碎片

    • 他们之间的收集方式

      CMS老年代 Card Table 引用了堆 全盘扫描整个老年代 耗时 有空间碎片

      G1优先收集垃圾比较多的区域 region

    • G1设计的初衷

      以前GC收集器扫描整个老年代,新生代和老年代需要是连续空间

  4. 如何减少GC的频率

    • 适当的增加堆内存的空间
    • 合理的设置G1垃圾收集器的停顿时间
    • 垃圾回收临界线 -XX:initialtingHeapOccupancyPercent=45(默认)
    • 增加垃圾回收线程数量
  5. 什么样的对象才是垃圾

    • 引用计数法

    • 可达性分析 GC Root

  6. 如何选择合适的垃圾收集器

    • 优先调整堆的大小让服务器自己来选择
    • 如果内存小于100M,使用串行收集器
    • 如果是单核,并且没有停顿时间要求,使用串行或JVM自己选
    • 如果允许停顿时间超过1秒,选择并行或JVM自己选
    • 如果相应时间最重要,并且不能超过1秒,使用并发收集器
  7. JVM参数

    1. 标准参数

      java -version/ -help

    2. -X 参数

      非标准参数:JDK版本变动会导致变动

      java -Xint/-Xcomp/-Xmixed Hotspot

      mixed混合模式 JVM自己选择

    3. -XX 参数

      • Boolean类型

        -XX:[+/1]name 启动或者停止

      • 非Boolean类型

        -XX: name=value

        -XX: maxHeapSize=100M

    4. 其他参数

      -Xms100M = -XX: InitiaHeapSize=100M 初始化堆内存

      -Xmx100M = -XX: MaxHeapSize=100M 最大化堆内存

      -Xss100M=-XX: ThreadStackSize=100M 栈内存

  8. 内存分析过程中会用到的一些指令

    • JPS 查看当前Java进行

    • Jinfo 查看或者修改JVM参数 试试修改Jinfo -flag name = value PID

    • Jstat class/gc

    • Jstack PID

    • Jmap: 生成堆内存的快照

      Jmap -heap PID

      生成快照文件: Jmap dump:format = b.file:heap.hprof PID

    • 分析内存

      • 查看内存工具

        • Jconsole

        • Jvisualvm(windows需要安装插件 Mac直接就可以在上面下载插件)

        • MAT

        • perfma 在线的 dump分析文件

      • 分析日志工具

        • gcviewer
        • gc easy 在线网站
  9. 垃圾收集发生的时机是什么时候

    GC由JVM自己完成,时间不确定,也可以手动调用System.gc(),手动调用会有一个问题,强引用类型无法清除掉,就算内存不够用,报异常,也不清除,需要了解强引用、软引用、弱引用、虚引用的区别

    • Eden区或S区不够用了 Minor GC
    • 老年代空间不够用了 Major GC
    • 方法区空间不够用了 Full GC
    • System.gc()->手动调用
  10. 评价一个垃圾收集器的好坏

    • 停顿时间
    • 吞吐量
    • GC次数
  11. 是否选用G1垃圾收集器的判断标准

    • 使用G1GC垃圾收集器

      -XX:+UseG1GC

    • 调整内存大小再获取gc日志分析

    • 调整最大停顿时间

    • 启动并发GC时,堆内存占用百分比

      并发周期,基于整个堆的使用率

      -XX: InitiatingHeapOccupancyPercent=45(默认)

  12. 调优G1

    • 尽量不调整新生代的大小,否则会破坏停顿时间,JVM是会自己进行调整的
    • 停顿时间,不要设置太严格,否则会增加GC次数,影响吞吐量
    • 对参数进行调整,增加标记线程的数量 concGCThreads = 10
    • Mixe混合调优
    • 适当增加堆内存大小
  13. 如果Full GC频繁怎么办?怎样减少Full GC次数?

    • 可以调整新生代:老年代的比例,稍微加大新生代,newRadio默认是2(1:2)
    • 调整停顿时间/吞吐量等,让其在新生代就被回收
  14. GC次数频繁,你会怎么办?

    • 为什么能够知道频繁?GC次数?CPU使用率高了?
    • 解决步骤:打印出gc日志->minor GC/major GC 结合工具看一下
    • 解决方法:
      • 适当增加堆内存的空间
      • 选择的垃圾收集器不合适
      • set pause time 是不是太严格了 strict/并发周期(堆内存使用率45% 调高一点)
  15. CPU持续飙升

    • 为什么能看到CPU升高呢?
    • 解决步骤:top->id->jstack/jinfo/jmap
    • 解决方法:
      • 集群
      • MQ
      • 业务层面,是否是线程死锁
  16. OOM怎么解决?

    • 如何发现的
    • 解决步骤:dump文件,日志->分析dump文件->MAT/其他工具
    • 解决方法:
      • 调整堆内存空间
  17. Young GC会有STW吗?

    不管什么GC,都会有Stop The World,只是发生时间的长短不同而已

  18. 内存泄漏和内存溢出

    • 内存泄漏

      对象无法得到及时的回收,持续占用内存空间,从而造成内存空间的浪费

    • 内存溢出

      内存泄漏到一定的成都就会导致内存溢出,但是内存溢出也有可能是大对象导致的

    • 内存泄漏和内存溢出OOM有什么区别?

      对象得不到回收,导致泄漏累积,最终会变为内存溢出

  19. 方法区中的回收主要是什么内容?

    • 分析

      方法区里存储的内容是什么?

      类信息、静态变量、常量池、没有用的类的信息、常量

    • 类的信息什么时候被回收呢?

      • 堆里面不再有该类的对象了
      • 加载该类的ClassLoader已经被回收了
      • java.lang.class对象不再有任何地方引用,反射也不能用–>可以回收,但并不是一定!!
  20. 不可达的对象一定要被收回吗?

    GCRoot->请注意 会被标记两次

    不可达对象->finalize()->不是垃圾对象,可能会有标记,自救恢复

  21. 什么是直接内存?

    直接内存是在java堆外的,直接向系统申请的内存空间,通常访问直接内存的速度会优于java堆,因此出于性能的考虑,读写频繁的场合可能会考虑使用直接内存

  22. 安全点和安全区域

    • 安全点

      线程可以暂停的时间点,一般是耗时较长的执行过程中发生的,不会影响到执行速度,如果在耗时短的执行过程中发生的,会有影响

    • 安全区域

      就是在一定区域内,都可以进行暂停的发生

    • 抢先式中断

      目前已经没有虚拟机用这种方式了

    • 主动式中断

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值