一、垃圾回收
1.如何判断对象可以回收
(1)引用计数法
存在循环引用问题, Java未使用这种算法
在引用计数法中,每个对象都有一个引用计数器,记录着指向该对象的引用数量。当引用计数器为零时,表示没有任何引用指向该对象,该对象可以被释放,回收其占用的内存。
(2)可达性分析法
根对象:肯定不能被垃圾回收的对象
2.Java引用类型
1.强引用
被GC-Root引用
2.软引用
没有被强引用, 垃圾回收时内存不够,软引用被回收
3.弱引用
没有强引用,只要发生垃圾回收,弱引用会被回收掉
软引用 弱引用也占用一定的内存,对 它两进行释放,通过引用队列
4. 虚引用
必须配合引用队列使用,虚引用对象被垃圾回收时,虚引用 自己放入引用队列,由一个线程释放内存
5.终结器引用
Object中有finallize方法,对象重写finallize方法 ,并且没有强引用 引用它,可以被当作垃圾回收
软引用实例
弱引用实例
垃圾回收算法
1.标记清除算法
标记清除算法(Mark-Sweep Algorithm)是一种常见的垃圾回收算法,用于自动管理动态分配的内存空间。其原理如下:
标记阶段(Mark):从根对象开始,通过引用链追踪,标记所有的活动对象。标记过程中,将活动对象的标记位设置为有效状态,表示这些对象是可达的,不会被回收。
清除阶段(Sweep):在标记阶段完成后,遍历整个内存空间,将未被标记的对象视为垃圾对象,将其所占用的内存空间释放,以便下次分配给新的对象使用。
优点:速度快
缺点:容易造成内存碎片
标记清除算法通过标记和清除的过程,将不再被使用的内存空间回收,以避免内存泄漏和内存碎片的问题。
然而,标记清除算法也存在一些缺点,如清除阶段会产生内存碎片,可能会导致内存分配的效率降低。
2.标记整理算法
- 标记阶段:
与其他垃圾回收算法一样,标记-整理算法从根对象开始遍历整个对象图,标记所有与根对象可达的对象,即被引用的对象。 - 整理阶段:
在整理阶段,标记-整理算法会对内存空间进行整理,将所有存活的对象移动到一端,而未标记的对象则被认为是垃圾对象。
移动存活对象的过程中,标记-整理算法会保持存活对象之间的相对位置关系,从而确保所有存活对象在整理后仍然是连续的。 - 回收阶段:
在整理阶段完成后,标记-整理算法会回收并释放未标记的垃圾对象所占用的内存空间,从而实现垃圾回收。
优点:没有内存碎片
缺点:速度慢
3.复制算法
复制算法的基本思想是将内存空间划分为两个大小相等的区域,通常称为"From"空间和"To"空间。在垃圾回收过程中,首先将所有存活的对象从"From"空间复制到"To"空间中,然后对整个"From"空间进行垃圾回收,将未复制的垃圾对象清理掉。在下次垃圾回收时,交换"From"空间和"To"空间的角色,继续进行复制和回收操作。这样,"From"空间和"To"空间的角色不断交替,实现了垃圾对象的回收和内存空间的复用。
优点:不会产生碎片
缺点:需要占用双倍内存
分代回收
新生代空间不足,触发MinorGC,先标记
eden(伊甸园)满了,采用复制算法将存活的对象复制到TO中,幸存的对象寿命+1
交换From和To
第二次垃圾回收
当对象寿命超过阈值(15),晋升到老年代
FullGC
老年代空间不足,先尝试进行一次MinorGC ,之后空间任然不足,触发FullGC
Stop the world 暂停其他线程,进行垃圾回收
4.垃圾回收器
4.1 串行垃圾回收器
- 单线程
- 堆内存较小 适合个人电脑
新生代:复制算法
老年代: 标记 + 整理 算法
4.2 吞吐量优先
- 多线程
- 堆内存较大,多核CPU
- 单位时间内,STW时间最短 0.2 0.2 = 0.4 只执行了两次
多个垃圾回收线程并行执行,不允许用户工作线程运行
4.3响应时间优先
- 多线程
- 堆内存较大,多核CPU
- 尽可能让单次STW时间短 0.1 0.1 0.1 0.1 0.1 = 0.5
与用户线程并发执行,在工作的同时用户线程也能工作。工作代老年代
5. G1 垃圾回收器
5. 整体过程,分为三个部分
5.1 Young Collection
新生代内存紧张,放入幸存区
幸存区S有一部分晋升到老年区O
5.2 Young Collection + CM (并发标记)
初始标记: 标记根对象
并发标记: 从根对象触发,顺引用链找到其他标记对象(老年代占用比例达到一定阈值,进行并发标记)
5.3Mixed Collection混合收集
混合收集阶段优先回收垃圾最多的区,不是收集所有老年代的垃圾 。目的暂停时间短
5.4 FullGC
不懂