jvm面试学习笔记

146 阅读5分钟

JVM体系结构

gc作用区域为方法区和堆,灰色部分主要是线程私有。 image.png

常见的垃圾回收算法

  • 引用计数

image-20200318184508982

在双端循环,互相引用的时候,容易报错,目前很少使用这种方式了

  • 复制

复制算法在年轻代的时候,进行使用,复制时候有交换

image-20200318184759295

image-20200318184820787

优点:没有产生内存碎片

  • 标记清除

先标记,后清除,缺点是会产生内存碎片,用于老年代多一些

image-20200318184944878

  • 标记整理

标记清除整理

image-20200318185100936

但是需要付出代价,因为移动对象需要成本

Java8 JVM内存结构

基本结构与之前类似,只是Java8取消了之前的“永久代”,取而代之的是“元空间”——Metaspace,两者本质是一样的。“永久代”使用的是JVM的堆内存,而“元空间”是直接使用的本机物理内存。

谈谈你对GCRoot的理解

jvm在回收时,要确定什么是垃圾,主要有两种算法

  • 引用计数法,没办法处理循环引用,java没有使用
  • 可达性分析法(枚举根节点做可达性分析)
    • 所谓GCRoots是一组必须活跃的引用。通过一系列名为GCRoots的对象作为起始点,从起始点向下搜索。如果一个对象到GCRoots没有任何引用链相连时,此对象不可用。

以下四种可以作为GCRoots对象

  • 虚拟机栈(栈帧中局部变量区)中引用的对象
  • 方法区中类静态属性的引用对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象

如何查看jvm系统默认值

JVM参数类型

  • 标配参数
    • -version
    • -help
    • java -showversion
  • X参数
    • -Xint 解释执行
    • -Xcomp 第一次使用就编译成本地代码
    • -Xmixed 混合模式
  • XX参数
    • Boolean类型
      • 公式:-XX:+/-某个属性值
      • case:是否打印GC细节:-XX:+PrintGCDetails
    • KV设置类型
      • 公式: -XX:属性key=属性值value
      • case:-XX:MetaspaceSize=128m,-XX:MaxTenuringThreshold=15
    • jinfo举例,如何查看当前运行程序的配置
      • jiofo -flag 参数 pid 查看该pid指定参数信息
      • jinfo -flags pid 查看该pid所有参数信息
    • 题外话(坑题) -Xms和-Xmx如何解释?-Xms等价于-XX:InitialHeapSize, -Xmx等价于-XX:MaxHeapSize

查看jvm默认值

  • -XX:+PrintFlagsInitial,java -XX:+PrintFlagsInitial -version
  • -XX:+PrintFlagsFinal 打印最终值
  • -XX:+PrintCommandLineFlag 常用参数查看

jvm常用基本参数配置有哪些

  • -Xms 初始堆内存 默认1/64内存大小 等价于-XX:InitialHeapSize
  • -Xmx 最大堆内存 默认1/4内存大小 等价于-XX:MaxHeapSize
  • -Xss 设置单个线程栈的大小,默认512~1024k 等价于-XX:ThreadStackSize,默认情况下查询值 jinfo -flag ThreadStackSize pid为0,因为只有window系统依赖于虚拟内存,诸如linux为1024k
  • -Xmn 设置年轻代大小,一般不用调
  • -XX:MetaspaceSize 设置元空间大小,元空间不同于永久代,不在虚拟机 中,使用本地内存,默认情况下元空间大小仅受本地内存限制
  • -XX:+PrintGCDetails 打印GC详情
  • -XX:SurvivorRatio 默认值为8,即8/1/1的Eden,s0,s1区的比例
  • -XX:NewRatio 年轻代和老年代比例,默认值为2,新生代1:老年代2
  • -XX:MaxTenuringThreshold 设置垃圾最大年龄 默认15,如果为0则不经过s区,直接进入养老区。对于老年代较多的应用可以提高效率。如果设置值较大,年轻代对象会在survivor区进行多次赋值,增加在年轻代被回收概率。

谈谈你对强引用弱引用软引用虚引用的区别。

  • 强引用 无论如何也不回收 哪怕oom(默认支持模式),只要有对象指向,就不回收
  • 软引用 SoftReference内存足够的前提下不收,不够GC才收
    • 如果应用要读取大量本地图片,每次读取图片都从硬盘读取,影响性能,一次全加载到内存中可能会内存溢出,此时使用软引用合适。
  • 弱引用 WeakReference无论内存够不够用,只要GC,一律回收,上述场景弱引用也适用
    • WeakHashMap GC之后 kv消失
  • 虚引用 PhantomReference 不会决定对象的生命周期,如果一个对象仅有虚引用,那么它和没有引用一眼个,任何时候都可能被GC掉,需要和引用队列ReferenceQueue联合使用。get方法总是返回null,其意义在于说明一个对象已经进入finalization阶段,可以被GC回收,用来实现比finalization机制更灵活的回收操作。死之前在引用队列有个通知机制,一般用不到
    • 引用队列 回收前需要被引用队列保存下
    Object o1 = new Object();
    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
    WeakReference<Object> weakReference = new WeakReference<>(o1, referenceQueue);
    
    System.out.println(o1);
    System.out.println(weakReference.get());
    System.out.println(referenceQueue.poll());
    
    o1 = null;
    System.gc();
    Thread.sleep(500);
    
    System.out.println(o1);
    System.out.println(weakReference.get());
    System.out.println(referenceQueue.poll());
    
    • GC前:
      • java.lang.Object@28d93b30
      • java.lang.Object@28d93b30
      • null
    • GC后
      • java.lang.Object@28d93b30
      • java.lang.Object@28d93b30
      • null
    • 虚引用举例
            Object o1 = new Object();
            ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
            PhantomReference<Object> phantomReference = new PhantomReference<>(o1, referenceQueue);
    
            System.out.println(o1);
            System.out.println(phantomReference.get());
            System.out.println(referenceQueue.poll());
    
            o1 = null;
            System.gc();
            Thread.sleep(500);
    
            System.out.println(o1);
            System.out.println(phantomReference.get());
            System.out.println(referenceQueue.poll());
    
      - GC前
          - java.lang.Object@28d93b30
          - null
          - null
      - GC后
          - null
          - null
          - java.lang.ref.PhantomReference@1b6d3586
          
    

谈谈你对oom的认识

属于Error错误

  • StackOverFlowError

    • 递归调用自己,会出现此错误,即超过栈内存。
  • OutOfMemoryError:java heap space

    • 对象过多,超过堆内存
  • OutOfMemoryError:GC overhead limit exceeded

    • GC时间过长,超过98%时间用来做GC并且回收了不到2%内存,连续多次GC都只回收了不到2%内存才会抛出。
  • OutOfMemoryError:DDirect buffer memory

  • OutOfMemoryError:unable to create new native thread

  • OutOfMemoryError:Metaspace