美文网首页
GC垃圾回收

GC垃圾回收

作者: i小雨 | 来源:发表于2021-03-12 15:39 被阅读0次

    GC垃圾回收算法
    借鉴一借鉴二

    • 1、引用计数法

    思想:每一个对象都有一个counter,只要有任何一个对象引用了该对象,则其counter加1,当引用失效时,counter减1,当counter为0时,对象不存在任何引用,在GC时被清除
    优点:思想和实现都很简单(只需要为每一个对象配备一个整型的计数器)
    缺点:
    1、无法处理循环引用问题,可能会造成死锁:比如对象A和对象B互相引用,但是不存在其他对象引用A和B,此时A和B属于不可达的对象,即垃圾对象,但是counter无法识别此类垃圾对象间的互相引用,从而引起内存泄露,不能GC
    2、counter要求在每次引用生效和失效时进行加减法操作,在一定程度上影响系统性能

    • 2、标记清除法

    思想:该算法先标记,后清除,将所有需要回收的对象进行标记,然后清除;这种算法的缺点是:效率比较低;标记清除后会出现大量不连续的内存碎片,这些碎片太多可能会使存储大对象会触发GC回收,造成内存浪费以及时间的消耗。
    优点:只存在循环引用不存在其他引用的对象不会被标记,解决了循环引用问题

    缺点:可能会产生空间碎片(不连续的内存空间),不连续的内存空间在内存分配时的工作效率低于连续的内存空间,尤其是对大对象的的内存分配

    • 3、复制算法

    思想:复制算法将可用的内存分成两份,每次使用其中一块,当这块回收之后把未回收的复制到另一块内存中,然后把使用的清除。这种算法运行简单,解决了标记-清除算法的碎片问题,但是这种算法代价过高,需要将可用内存缩小一半,对象存活率较高时,需要持续的复制工作,效率比较低。

    • 4、标记压缩法(标记清除压缩法)

    思想:标记压缩法是对标记清除法的优化,所以也叫标记清除压缩法。和标记清除法一样,先标记所有的可达对象(存在引用的对象),不同的是,标记完成后并不是直接清除未标记的垃圾对象,而是将所有的被标记的对象(即存活对象)压缩到内存空间的一端后在清理边界外所有的空间。

    • 5、分代收集算法:

    思想:将内存空间根据对象的特点不同进行划分,选择合适的垃圾回收算法,以提高垃圾回收的效率。
    GC过程:因为不同的对象使用的算法不一致,所以GC的过程也不一样,例如,新生代使用复制算法,老年代使用标记压缩法。详细在下面分析

    分代收集:
    借鉴

    1、堆内存内部结构:

    所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。堆被划分为新生代和老年代,新生代又被进一步划分为Eden(伊甸园)和Survivor(幸存者)区,老年代,在后面不是堆区是永恒代(方法区),为了进一步了解堆内存里的结构,我们先要了解一种垃圾回收算法,分代算法,回收垃圾的过程,通过这个过程的分析,进一步了解堆区里的结构细节,结构图如下所示:


    图片.png

    2、收集过程:

    图片.png
    图片.png
    当幸存对象的年龄达到某个值后,就会从年轻代进入老年代。
    图片.png

    最后的永恒代,放常用库文件和方法。

    Eden和survivor的比例为8:1,年轻代中的对象基本都是朝生夕死的(80%以上),老年代比年轻代内存大。如果老年代内存满了,就会触发major GC或者full GC。触发full GC就会出现所谓的STW(stop the world)现象。即所有的进程都挂起等待清理垃圾。

    major GC是回收老年代的垃圾。Full GC是回收老年代和年轻代的垃圾。

    3、GC如何判断对象可以被回收:

    • 引用计数法:每个对象有一个引用计数属性,新增一个引用是计数+1,引用减少一个计数-1,计数为0时可以被回收。
    • 可达性分析法:
      许多Java的垃圾收集器都使用了引用的根集GC Roots,作为分析对象存活与否的依据。引用的根集是正在执行的Java程序随时都可以访问引用的变量的集合——也就是存在堆栈或是静态存储空间上的引用变量。从这些根集变量出发可直接或是间接到达的对象,垃圾收集器会认为这些对象是生命尚存的对象;相对的从这些根集变量出发通过任意途径都无法到达的对象,就是死亡的,它们就会成为下一次垃圾收集的对象。

    4、GC Roots:

    图片.png

    所谓“GC Roots”的根集合,就是一组活跃的引用。
    基本思路就是通过一系列名为“GC Roots”的对象作为起始点,从这个被称为GC Roots的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链连接时,说明此对象不可用。也即给定一个集合的引用作为根出发,通过引用关系遍历对象图,能被便利到的对象就被判定为存活,没有被遍历到的被判定为死亡。

    - 可以作为GC Roots的对象有哪些?

    1、虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象
    2、方法区中的类静态属性引用的对象
    3、方法区中常量引用的对象
    4、本地方法栈中JNI(Native方法)引用的对象

    图片.png

    相关文章

      网友评论

          本文标题:GC垃圾回收

          本文链接:https://www.haomeiwen.com/subject/wydzqltx.html