一文了解GC垃圾回收
1 判断一个对象为垃圾对象的方法
-
引用计数法(弃用)
-
可达性分析算法
是否有指向GC root 的引用链,如果有,不是垃圾对象 ---->GC roo:即rt.jar包中内容
2 内存泄漏与内存溢出区别
泄漏:原本需要被回收的对象,没有被回收
溢出:内存空间不够用,导致溢出现象
例:
ThreadLocal
在购物车模块中,我们的实现思路是,无论登录与否,都可以添加购物车,但是在并发的情况下,就有可能会导致大量的userInfo(userkey或者UserId),如果这些
对象不能够及时被垃圾回收器清理掉,就有可能导致服务器内存不够用,从而导致服务器宕机,项目中为了解决这个问题,使用ThreadLocal的set方法保存用户对
象,通过观察源码发现,被ThreadLocal保存的对象具有弱引用的特性(发现即回收),这样就可以规避可能出现的OOM风险
3 对象引用方式
-
强引用(StrongReference)
永不回收
当一个对象被一个或多个以上的引用变量所引用时,它处于可达状态,不可能被系统垃圾回收。系统内存空间足够时,它不会被系统回收,程序也可以使用该
对象,当系统内存空间不足时,系统可能会回收它。
-
软引用(SoftReference)
内存不够就回收
系统内存空间足够时,它不会被系统回收,程序也可以使用该对象,当系统内存空间不足时,系统可能会回收它。软引用通常用于对内存敏感的程序中。
-
弱引用(WeakReference)
检测到就回收
和软引用很像,但是引用级别更低,对于弱引用而言,当系统垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占用的内存。当然,并不是说
当一个对象只有弱引用时,它就会立即回收——正如那些失去引用的对象一样,必须系统垃圾回收机制运行时才会被回收。
-
虚引用(PhantomReference)
虚引用主要用于跟踪对象被垃圾回收的状态,虚引用不能单独使用,虚引用必须和**引用队列联合(ReferenceQueue)**使用。单独使用虚引用没有太大意义。
虚引用主要作用就是跟踪对象垃圾回收的状态,程序可以通过检查与虚引用关联的引用队列中是否有给引用,从而了解虚引用的对象是否即将回收。
4 垃圾回收算法
1 复制算法
需要在内存中开辟两块同样大小的空间,用于复制没有被回收的对象,体现在新生区的设计思路,包含幸存0区 幸存1区
优点:
速度快
缺点:
浪费一定的内存空间
2 标记清除
扫描了整个空间两次,先进行垃圾对象的标记,在进行垃圾对象的清理
优点 :
实现简单
缺点:
- 回收效率低—>扫描了整个空间两次:第一次:标记存活对象,第二次:清除没有标记的对象
- 产生内存碎片对于需要使用连续内存空间的对象(比如数组对象)的时候,会造成空间浪费,堆利用率低
3 标记压缩
先进行垃圾对象的标记,对内存进行整理,最后对垃圾对象进行清理
优点:
内存整理,堆的浪费少,利用效率高
缺点:
至少需要扫描了整个空间三次,速度慢
4 分代收集
频繁回收新生区,较少回收养老区,基本不动元空间
新生区:用复制算法
养老区:用标记清除算法 或者 标记压缩算法
5 垃圾回收器
1 串行回收器
serial GC 新生区的垃圾对象回收 复制算法 单线程的收集器,收集垃圾时,必须stop the world
serial Old GC 养老区的垃圾对象回收 标记整理
2 并行回收器
(jdk8默认使用的垃圾回收器组合) 复制算法
parallel GC 新生区的垃圾对象回收
parallel Old GC 养老区的垃圾对象回收 标记整理
3 并发回收器
CMS(Concurrent Mark Sweep) 一款非常流行的并发回收器,目前java市面上依然有大量的公司使用该回收器回收养老区的对象,采用的垃圾回收算法::标记清除算法
parNew parallel new 并行回收新生区的一个回收器,采用的垃圾回收算法:复制算法
G1 jdk9之后默认的垃圾回收器,采用的垃圾回收算法: 标记整理算法
-
Region
- 红色:伊甸园区
- S+红色:幸存区
- 蓝色:养老区
- H+蓝色:大对象
-
Rset
用于记录一个Region中的对象是否被其他Region引用的情况