Administrator
发布于 2022-06-15 / 9 阅读
0
0

面试点杂项

::: tip volatile
两个核心特性

  • 保证变量对所有线程的可见性。可见性是指:当一条线程修改了这个变量的值,新值对其他线程来说是可以立即得知的。
  • 禁止指令重排序
    :::

::: tip JVM GC类型

  • Minor GC:针对新生代的GC,通常使用标记-清除标记-复制
  • Old GC:针对老年代GC,为了长久的性能考虑,通常使用标记整理,CMS会使用标记-清除,但是当清除后空间还是不够时,会触发一次标记-整理的Full GC,此时会加大单次GC的时间长度
  • Full GC:针对全堆GC,会单独触发Minor GC与Old GC,具体什么算法看垃圾收集器
  • Mix GC:混合着新生代与老年代的GC,G1专有

:::

::: tip JVM GC 算法

  • 根节点枚举

  • 三色标记
    • 初始状态所有对象为白色,根节点枚举的是黑色,根节点直接引用的会变为黑色,如果还有未标记的引用,则为灰色,最终为白色的全部进行回收
    • 回收线程与用户线程同时进行时,会出现对象被迁移的情况:新增黑色对象对白色对象的引用,删除了全部从灰色对象对白色对象的直接或间接引用
      • 增量更新 - 解决黑色新增白色节点,会以黑色对象为根,按照新增的链路进行标记
      • 原始快照 - 解决灰色失去白色节点,会以灰色对象为根,按照原始的链路进行标记
  • 回收算法
    • 分代收集理论
      • 强分代假说和弱分代假说:大多数对象朝生夕灭,熬过越多次垃圾回收的对象越难回收。所以分为新生代和老年代
      • Minor GC - 针对新生代的GC
      • Major GC - 针对老年代的GC
      • Full GC - 针对全堆的GC
    • 标记 - 清除
      • 速度快,但是会出现内存碎片,导致内存泄露
    • 标记 - 复制
      • 速度中,不会出现因内存碎片出现的内存泄露,但是会增加内存消耗(新增了Eden区,整个新生代分为一个Survivor和两个Eden区,比例为8:1:1)
    • 标记 - 整理
      • 速度慢,但是内存利用率很高
        :::

::: tip Full GC的触发场景

  • 手动调用System.gc(),但是具体什么时候调用还得看垃圾收集器的
  • Eden区进行老年代晋升时内存不够,触发内存担保,而老年代空间本身也不够时,进行Full GC
  • CMS进行Old GC后发现空间还是不够时进行Full GC
    :::

::: tip 有哪些类加载器

  • 启动类加载器:BootstrapClassLoadler
  • 扩展类加载器:ExtClassLoader
  • 应用程序类加载器:
    :::

::: tip JVM 双亲委派
什么是双亲委派
类由类加载器进行加载,双亲委派会将类加载器分层,当类加载器收到一个加载类的请求时,会将类加载的请求委托给父加载器处理。每层类加载器都会判断当前类是否已加载,是否可以加载。当父加载器无法处理时,才在本地进行的类加载。

双亲委派有什么优点

  • 避免重复加载类
  • 避免核心类被篡改
  • 解决了各个加载器中基础类统一的问题
    :::

::: tip 什么时候需要破坏双亲委派
主要场景
在于JDK需要调用三方库时需要破坏,因为双亲委派并不能使用子加载器进行类加载,而JDK位于启动类加载器(顶层),三方库位于系统类加载器(classPath下),此时JDK调用三方库中类时,如果无法绕开双亲委派,就会出现无法加载类的错误。
具体实现
JDK提供了SPI(服务提供者接口),允许第三方厂家提供接口的实现类,此时SPI位于JDK的启动类加载器,三方实现类位于系统类加载器。
使用线程上下文类加载器(TCCL:Thread Context ClassLoader)可以在Thread中调用setContentClassLoadgetContentClassLoad来控制线程上下文类加载器,如果不设置,默认获取父类的线程上下文类加载器,初始的默认应用上下文类加载器是ApplicationClassLoader。

实际情况
程序运行中,即可通过Thread.currentThread().getContextClassLoad()获取当前线程的上下文类加载器来加载三方类。
:::

::: tip 常见的JVM调优方法有哪些

  • console
  • jProfile
  • VisualVM
  • Dump线程详细信息:查看线程内部运行情况
  • jmap -heap pid :查看堆栈使用信息,Xmx调整为老年代使用大小的3倍
    :::

::: tip Spring Bean 生命周期
Description{{{width="auto" height="auto"}}}
:::

::: tip JVM 调优 - jps
使用场景:查看有哪些Java进程、启动参数的信息

jps     //查看当前用户的Java进程
jps -q  //仅输出VM标识符,PID
jps -l  //输出jar包完整的存放路径或者完整的包名
jps -m  //输出传递给main方法的参数
jps -v  //输入当前用户下的Java进程的启动参数
jps -V  //效果同jps

:::

::: tip JVM 调优 - jstat
使用场景:查看GC信息,可以用做监控信息,侧重GC的次数与结果

  jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
  jstat -gc pid           //查询一次进程 pid 的垃圾收集情况
  jstat -gc pid 250 20    //查询进程 pid 的垃圾收集情况,每250毫秒查询一次,一共查询20次。
  jstat -gccause pid      //额外输出上次GC原因
  jstat -calss pid        //类装载、类卸载、总空间以及所消耗的时间
  jstat –gcnew pid        //监视新生代GC的状况
  jstat –gcold pid        //监视老年代GC的状况

:::

::: tip JVM 调优 - jmap
使用场景:查看堆的使用情况,侧重当前的使用情况

  jmap -heap pid          //查看java 堆(heap)使用情况和堆内存的初始化值(易读,清晰)
  jmap -histo pid         //查看堆内存(histogram)中的对象数量及大小 (实用)
  jmap -histo:live pid    //JVM会先触发gc,然后再统计信息 (gc后对象一下少了一半)
  jmap -dump:format=b,file=heapDump pid   //将内存使用的详细情况输出到文件,之后一般使用其他工具进行分析。

:::

::: tip JVM 调优 - jstack
使用场景:查看进程的线程使用情况

jstack pid     //查看线程情况
jstack -F pid  //正常输出不被响应时,使用该指令
jstack -l pid  //除堆栈外,显示关于锁的附件信息

参考文章:Java——命令jps、jstat、jmap、jstack、jhat、jinfo
:::

::: tip JVM常见问题
频繁GC问题或内存溢出问题
一、使用jps查看线程ID
二、使用jstat -gc 3331 250 20 查看gc情况,一般比较关注PERM区的情况,查看GC的增长情况。
三、使用jstat -gccause额外输出上次GC原因
四、使用jmap -dump:format=b,file=heapDump 3331生成堆转储文件
五、使用jhat或者可视化工具(Eclipse Memory Analyzer 、IBM HeapAnalyzer)分析堆情况。
六、结合代码解决内存溢出或泄露问题。

死锁问题
一、使用jps查看线程ID
二、使用jstack pid查看线程情况

OutOfMemery如何处理
首先线上应用的jvm配置要养成良好的习惯,增加一下配置则可以在jvm发生 oom的时候自动dump日志了 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/log/dump/jvm-oom.log

总结
1.如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。
2.要制作堆Dump可以直接使用jvm自带的jmap命令
3.可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。
:::

::: tip JVM 加载

  • 加载 - 加载二进制字节码,将字节码对应的数据结构加载到方法区/元空间
  • 验证 - 验证字节码是否符合jvm的要求,有点像判断是否能编译通过
  • 准备 - 为静态变量分配内存空间,设置为零值,实例变量在new时分配空间
  • 解析 - 将字节码中的符号运用(比如:引用Date类)解析成运行时的内存中的地址引用
  • 初始化 - 将类的静态变量,由默认零值变为自定义的初始值
  • 使用 - 执行静态代码块、自己编写的new之类的业务代码
  • 卸载 - 类卸载,可以进行垃圾回收,但是这部分的垃圾回收通常效果都不好,因为卸载的要求比较苛刻,需要类没有任何地方使用,回收后的效果也不是很明显,通常不研究,而且在1.8后,将类的加载放在了元空间里,主要受机器内存大小的限制
    :::

::: tip 引用 - 强、软、弱、虚

  • 强引用 - 普通new出来的变量,只有在退出方法后,触发GC时才能回收
  • 软引用 - 描述一些有用但非必须的对象,继承于SoftReference,在将要出现内存溢出之前进行回收,通常可用来做缓存
  • 弱引用 - 比软引用更弱,描述一些非必须的对象,继承于WeakReference,当垃圾收集器开始工作时,无论内存是否充足,都会被回收
  • 虚引用 - 最弱的一种引用关系,继承于PhantomReference,唯一用处在于对某个对象被回收时能做一个通知
    :::

::: tip List 和 Map 区别
在此输入内容
:::


评论