JVM体系结构
gc作用区域为方法区和堆,灰色部分主要是线程私有。
常见的垃圾回收算法
- 引用计数
在双端循环,互相引用的时候,容易报错,目前很少使用这种方式了
- 复制
复制算法在年轻代的时候,进行使用,复制时候有交换
优点:没有产生内存碎片
- 标记清除
先标记,后清除,缺点是会产生内存碎片,用于老年代多一些
- 标记整理
标记清除整理
但是需要付出代价,因为移动对象需要成本
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
- Boolean类型
查看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