垃圾检测和回收算法

833 阅读3分钟

可以点开原文查看详情哦

垃圾回收的作用

垃圾回收可以避免系统由于内存泄露导致的内存溢出。

  1. 内存泄露:系统中无用对象还占用内存
  2. 内存溢出:系统中对象占用内存,导致无法分配内存给新的对象

内存泄露会引起内存溢出但内存溢出不一定是内存泄露引起。

检测垃圾

引用计数法 Reference Count

每个对象都有一个引用计数器,对象被引用时该计数器就+1,引用失效就-1,当该对象引用计数器为0时,该对象就是垃圾, 引用计数法无法解决循环引用的问题 。

20201210 111847屏幕截图.png

D对象被A、B、C三个对象引用,D对象的引用计数为3所以D对象为存活对象不能被回收。

20201210 112254屏幕截图.png

A、B、C三个对象被互相引用,它们三个对象的引用计数为1,但没有任何有效引用指向它们,它们会被判定为存活对象,这样就会造成内存泄露。所以引用计数法无法处理循环引用的问题。

根可达算法GC Root

根可达算法定义凡是被根对象引用的对象就是存活对象,常见的根对象有:栈帧中引用的对象,常量引用的对象、静态变量引用的对象、JNI引用的对象。

从上述可以得出:根可达算法可以处理循环引用的问题。

20201210 113036屏幕截图.png

A、B、C、D直接或间接的被根对象引用,这四个对象为存活对象不能被清楚,F对象虽被E对象引用但没有被根对象引用它们是无用对象会被GC。

垃圾回收算法

检测到垃圾后,垃圾回收器就需要回收垃圾,但是如何高效的回收垃圾呢? 下面介绍3种常见的垃圾回收算法,这三种算法在适合的场景才会最高效,所以衍生出了目前最常用的分带收集算法(Generational Collection),会在JDK1.8分代模型和分代算法讲述。

复制算法 Copying

把系统使用的内存一分为二,分配对象只会在一块区域中分配,当这一块区域分配满以后就把存活对象复制到另一块区域并清空刚分配内存的区域。该算法优点只遍历一次内存区域,不会产生内存碎片但该算法浪费内存空间,导致内存空间膨胀一倍。 20201210 131926屏幕截图.png

标记清除 Mark Sweep

该算法分为两个步骤标记-清楚,在标记阶段标记无用对象,在清楚阶段清楚无用对象。该算法的缺点会导致内存碎片。 20201210 132130屏幕截图.png

标记压缩 Mark Compact

标记压缩算法就是在标记清除后增加了一步整理内存的步骤,在标记清除后会产生内存碎片,所以清除后我们把存活对象移向内存的右端,这样就不会有内存碎片了。 是不是觉得此方法最好,其实不然,因为你在移动存活对象的时候会改变对象的引用地址,要暂停系统一段时间简称STW(Stop the World)。 20201210 132325屏幕截图.png

写在最后

欢迎大家关注我的公众号【有一只基的程序猿】,一起交流Java、大数据,文章对应的脑图也会放在公众号里。 点关注,不迷路!!!

Ps: 如想知道基为何物,公众号一探究竟!!!

博客地址: www.fizzed.top