zoukankan      html  css  js  c++  java
  • 垃圾回收算法

    前面介绍了如何去识别和标记垃圾,现在主要介绍,如何去回收(处理、删除)这些垃圾?

    你也许会想,找到了直接删掉不就行了吗?

    恭喜你,已经学会了一个很重要的算法。

    标记-清除(Mark-Sweep)

    标记-清除算法,主要分为两个步骤,标记 和 清除。标记,就使用之前说过的 可达性分析算法,即可进行标记。

    就是我们根据 GC Roots 标记出存活对象,然后将垃圾对象进行清除即可。

    就是这么简单。

    但是这种算法主要有如下缺点:

    会产生大量的内存碎片。内存空间不再连续,对于一些大对象连续的对象结构来说,无非是浪费内存的行为。

    标记-复制

    为了解决上面的问题,内存碎片的问题,有种算法叫做垃圾-复制算法出现了。

    注意,我们将一个大内存分为 A B 两个部分。然后在一个内存中进行数据的存储。然后进行垃圾回收的时候,将标记出来的存活对象,直接复制到 B 空闲内存中,复制完成后,A 内存的全部空间都是可用的了。

    在介绍其缺点之前,先明确一点:

    只要移动了存活对象,相对而言,都会比较耗时,这个是由 Java 内存对象存储结构决定的。

    这就是Java 存储对象的结构布局,首先栈中保存指向Java堆中的引用,然后Java堆中有着指向方法区的引用。

    所以,如果我们移动了 Java 堆中的对象,那么Java栈中的引用就得进行变动。

    像我们之前说的 标记-清除 算法就没这个问题,因为它不移动存活对象,只是单纯删除不用的对象。

    回到我们的 标记-复制算法,如果每次复制的时候,有大量的对象需要复制,那么时间开销就很大了。

    标记-整理(标记-压缩)

    现在看下标记-整理算法,注意看上面的部分,当我们标记出存活对象的时候,我们就对他们进行移动整理,进而避免了垃圾碎片。

    但也就像我们之前说的,因为涉及到存活对象的移动,所以也有比较大的时间开销。

    分代收集算法

    我们注意到上面三种算法,各自都有其缺陷和擅长的地方。

    • 标记-清除适合少量垃圾存在的时候
    • 标记-复制适合有大量垃圾存在的时候
    • 垃圾-整理算法适合少量垃圾的时候

    于是,因地制宜,按照对象的不同生命周期,提出了分代收集算法。

    • 弱分代假说:绝大多数对象都是朝生夕灭的
    • 强分代假说:熬过多次垃圾回收过程的对象,就越难消亡

    于是,根据这种特点,就把内存大致分为老年代、年轻代。

    年轻代中的对象,绝大多数很快就会消亡,所以存在大量的垃圾,可以采用标记-复制算法

    老年代中的对象,很少对象会消亡,所以存在少量垃圾,可以采用标记-清除,和标记整理算法。

    老年代 和 年轻代的更多细节,我们下次再说。

  • 相关阅读:
    ubuntu安装jdk的两种方法
    LeetCode 606. Construct String from Binary Tree (建立一个二叉树的string)
    LeetCode 617. Merge Two Binary Tree (合并两个二叉树)
    LeetCode 476. Number Complement (数的补数)
    LeetCode 575. Distribute Candies (发糖果)
    LeetCode 461. Hamming Distance (汉明距离)
    LeetCode 405. Convert a Number to Hexadecimal (把一个数转化为16进制)
    LeetCode 594. Longest Harmonious Subsequence (最长的协调子序列)
    LeetCode 371. Sum of Two Integers (两数之和)
    LeetCode 342. Power of Four (4的次方)
  • 原文地址:https://www.cnblogs.com/zhouzhiyao/p/13172306.html
Copyright © 2011-2022 走看看