- 为什么要了解垃圾回收?
- 排查内存溢出
- 排查内存泄漏
- 性能调优,排查并发瓶颈
- 如何判断对象是否死亡
- 引用计数法:有地方引用它,计数器就加1;当引用失效,计数器就减1;当计数器为0时的对象可被回收;它很难解决对象之间相互循环引用的问题
- 可达性分析算法:通过一系列的称为 “GC Roots” 的对象作为起点,向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。
- 不可达的对象并非“非死不可”:要真正宣告一个对象死亡,至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法,或 finalize 方法已经被虚拟机调用过时,虚拟机将这两种情况视为没有必要执行。被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被真的回收。
- Minor GC 和 Major GC/Full GC
- 新生代GC(Minor GC):指发生新生代的的垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快。
- 老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC经常会伴随至少一次的Minor GC(并非绝对),Major GC的速度一般会比Minor GC的慢10倍以上。
- JVM垃圾回收的主要区域在堆内存
注:在 JDK 1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域(永久代使用的是JVM的堆内存空间,而元空间使用的是物理内存,直接受到本机的物理内存限制)
- Eden与S1、S2内存区域的大小比列一般为 8:1:1
- 新生代与老年代的大小比列一般为 1:2
- 永久代的垃圾回收内容主要是:废弃常量和无用的类
- 新产生的对象会优先存入Eden区, 如果对象过大,则大对象会直接存入Old区
- 当Eden区无法再放入新的对象的时候,会触发Minor GC,对整个新生代进行GC(将Eden区回收存活的对象复制到S1区,同时给存活的对象年龄标记为1,清除Eden区;下次GC时将Eden区、S1区仍然存活的对象复制到S2区同时年龄+1,然后清空Eden区、S1区,每一次GC存活对象都会在S1、S2区来回移动(目的是防止内存碎片化,保证连续的内存空间),在这期间如果有存活对象的年龄达到15(默认值)时,对象将被移到Old区)
- 当S1区/S2区无法再存入新对象时对象会被直接存入Old区
- 当Old区无法再放入新的对象的时候,会触发Major GC/Full GC,对整个堆内存进行GC
- 当Perm区无法再放入新的对象的时候,会触发Major GC/Full GC,对整个堆内存进行GC
- 废弃常量
- 没有任何对象引用的常量
- 无用的类
- 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
- 加载该类的 ClassLoader 已经被回收。
- 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
- 垃圾收集算法
- 标记-清除算法:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象;易产生空间碎片
- 复制算法:将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收
- 标记-整理算法:首先标记出所有需要回收的对象,然后让所有存活的对象向一段移动,然后直接清理掉端边界以外的内存
- 分代收集算法:根据对象存活周期的不同将内存分为几块,根据各个年代的特点选择合适的垃圾收集算法(比如:java堆分为新生代和老年代)
- 垃圾收集器
- Serial收集器
- 串行收集器
- 新生代垃圾收集器,采用复制算法
- 简单而高效;单线程收集器;它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “Stop The World” ),直到它收集结束。
- Serial Old收集器
- 老年代垃圾收集器,采用标记-整理算法
- ParNew收集器
- 并行收集器
- 新生代垃圾收集器,采用复制算法
- Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现。
- Parallel Scavenge收集器
- 并行收集器
- 新生代垃圾收集器,采用多线程和复制算法
- 追求高吞吐量,高效利用CPU。吞吐量一般为99%, 吞吐量= 用户线程时间/(用户线程时间+GC线程时间)
- Parallel Old 垃圾收集器
- 并行收集器
- 老年代垃圾收集器,使用多线程和标记-整理算法。
- 追求高吞吐量,高效利用CPU
- CMS(Concurrent Mark Sweep)收集器
- 并行收集器
- 老年代来及收集器,采用标记-清除算法(收集结束时会有大量空间碎片产生)
- 一种以获取最短回收停顿时间为目标的收集器
- 对CPU资源非常敏感,CPU占用比较高
- G1(Garbage-First)收集器
- 并行收集器
- 采用标记-整理算法
- 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征.
- 在G1之前的其他收集器进行收集的范围都是整个新生代或者老年代,而G1不再是这样。使用G1收集器时,Java堆的内存布局就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。
- 垃圾收集器使用区域
- 上面为新生代收集器,下面是老年代收集器
- 如果两个收集器之间存在连线,就说明它们可以搭配使用
- 垃圾回收的JVM配置
- System.gc() 和 Runtime.gc()
- System.gc();内部调用的是 Runtime.getRuntime().gc();最后调用 public native void gc();
- Runtime.gc();首先,没有这个调用(方法不是静态的)
- 提示JVM进行垃圾回收,回收方式为Full GC,但是什么时候回收由JVM决定
参考:
https://blog.csdn.net/qq_34337272/article/details/82177383