垃圾回收的作用
垃圾回收可以避免系统由于内存泄露导致的内存溢出。
- 内存泄露:系统中无用对象还占用内存
- 内存溢出:系统中对象占用内存,导致无法分配内存给新的对象
内存泄露会引起内存溢出但内存溢出不一定是内存泄露引起。
检测垃圾
引用计数法 Reference Count
每个对象都有一个引用计数器,对象被引用时该计数器就+1,引用失效就-1,当该对象引用计数器为0时,该对象就是垃圾, 引用计数法无法解决循环引用的问题 。
D对象被A、B、C三个对象引用,D对象的引用计数为3所以D对象为存活对象不能被回收。
A、B、C三个对象被互相引用,它们三个对象的引用计数为1,但没有任何有效引用指向它们,它们会被判定为存活对象,这样就会造成内存泄露。所以引用计数法无法处理循环引用的问题。
根可达算法GC Root
根可达算法定义凡是被根对象引用的对象就是存活对象,常见的根对象有:栈帧中引用的对象,常量引用的对象、静态变量引用的对象、JNI引用的对象。
从上述可以得出:根可达算法可以处理循环引用的问题。
A、B、C、D直接或间接的被根对象引用,这四个对象为存活对象不能被清楚,F对象虽被E对象引用但没有被根对象引用它们是无用对象会被GC。
垃圾回收算法
检测到垃圾后,垃圾回收器就需要回收垃圾,但是如何高效的回收垃圾呢? 下面介绍3种常见的垃圾回收算法,这三种算法在适合的场景才会最高效,所以衍生出了目前最常用的分带收集算法(Generational Collection),会在JDK1.8分代模型和分代算法讲述。
复制算法 Copying
把系统使用的内存一分为二,分配对象只会在一块区域中分配,当这一块区域分配满以后就把存活对象复制到另一块区域并清空刚分配内存的区域。该算法优点只遍历一次内存区域,不会产生内存碎片但该算法浪费内存空间,导致内存空间膨胀一倍。
标记清除 Mark Sweep
该算法分为两个步骤标记-清楚,在标记阶段标记无用对象,在清楚阶段清楚无用对象。该算法的缺点会导致内存碎片。
标记压缩 Mark Compact
标记压缩算法就是在标记清除后增加了一步整理内存的步骤,在标记清除后会产生内存碎片,所以清除后我们把存活对象移向内存的右端,这样就不会有内存碎片了。
是不是觉得此方法最好,其实不然,因为你在移动存活对象的时候会改变对象的引用地址,要暂停系统一段时间简称STW(Stop the World)。
写在最后
欢迎大家关注我的公众号【有一只基的程序猿】,一起交流Java、大数据,文章对应的脑图也会放在公众号里。 点关注,不迷路!!!
Ps: 如想知道基为何物,公众号一探究竟!!!
博客地址: www.fizzed.top