• GC中常见的算法


    垃圾收集 Garbage Collection 通常被称为“GC”,程序运行期间,所有对象实例存储在运行时数据区域的heap中,当一个对象不再被引用(使用),他就需要被回收,在GC过程中,这些不需要被使用的对象从heap中回收,这样就会有空间循环被利用

    判断一个对象是否存活常用的有两种办法:1引用计数法,2可达性分析算法

    一:引用计数法

    假设有一个对象A,任何一个对象对A的引用,那么对象A的引用计数器+1,当引用消失时,对象A的引用计数器就-1,如果对象A的计数器的值为0,就说明对象A没有引用了,可以被回收。
    优点:
    • 实时性较高,无需等到内存不够的时候,才开始回收,运行时根据对象的计数器是否为0,就可以直接回收。
    • 在垃圾回收过程中,应用无需挂起。如果申请内存时,内存不足,则立刻报outofmember 错误。
    • 区域性,更新对象的计数器时,只是影响到该对象,不会扫描全部对象。

    缺点:

    • 每次对象被引用时,都需要去更新计数器,有一点时间开销。
    • 浪费CPU资源,即使内存够用,仍然在运行时进行计数器的统计。
    • 无法解决循环引用问题。(最大的缺点)

    二:可达性分析算法

    该算法的基本思路就是通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(即从GC Roots节点到该节点不可达),则证明该对象是不可用的。
    在java中可以当作GC Root根的的对象有一下几种
    • 虚拟机栈(栈帧中的本地变量表)中引用的对象
    • 方法区中类静态属性引用的对象
    • 方法区中常量引用的对象
    • 本地方法栈中JNI(即一般说的Native方法)引用的对象

    三:标记清除算法(老年代)

    标记-清除算法分为两个阶段,标记(mark)和清除(sweep).

    在标记阶段,GC从根对象开始进行遍历,对从根对象可以访问到的对象都打上一个标识,一般是在对象的header中,将其记录为可达对象。

    而在清除阶段,GC对堆内存(heap memory)从头到尾进行线性的遍历,如果发现某个对象没有标记为可达对象-通过读取对象的header信息,则就将其回收。

    缺点:

    • 效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要停止应用程序,对于交互性要求比较高的应用而言这个体验是非常差的。
    • 通过标记清除算法清理出来的内存,碎片化较为严重,因为被回收的对象可能存在于内存的各个角落,所以清理出来的内存是不连贯的。

    优点:

    • 解决了引用计数法中无法解决的循环引用问题

    四:标记整理算法(老年代)

    标记压缩算法是在标记清除算法的基础之上,做了优化改进的算法。和标记清除算法一样,也是从根节点开始,对对象的引用进行标记,在清理阶段,并不是简单的清理未标记的对象,而是将存活的对象压缩到内存的一端,然后清理边界以外的垃圾,从而解决了碎片化的问题。

    优缺点同标记清除算法,解决了标记清除算法的碎片化的问题,同时,标记压缩算法多了一步,对象移动内存位置的步骤,其效率也有有一定的影响。

    五:复制算法(新生代)

    复制算法的核心就是,将原有的内存空间一分为二,每次只用其中的一块,在垃圾回收时,将正在使用的对象复制到另一个内存空间中,然后将该内存空间清空,交换两个内存的角色,完成垃圾的回收。如果内存中的垃圾对象较多,需要复制的对象就较少,这种情况下适合使用该方式并且效率比较高,反之,则不适合
      当Eden空间将要满的时候第一次触发YGC,将还有引用的对象复制到from区同时每个对象的年龄将会+1,等到了默认值15岁的时候就会被移入到old区,此时to区还是空的,同时清空Eden区,接下来再进行YGC的时候会将Eden区和from区还存活着的对象移入到to区,同时清空Eden区和from区,然后将form区和to进行交互,谁是空的谁变为to区。
    GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
    据统计,新生代的对象朝生夕死,90%以上的对象都无法活过eden区
     
    优点:
    • 在垃圾对象多的情况下,效率较高
    • 清理后,内存无碎片
    缺点:
    • 在垃圾对象少的情况下,不适用,如:老年代内存
    • 分配的2块内存空间,在同一个时刻,只能使用一半,内存使用率较低

    XX:PretenureSizeThreshold (默认值为0)的意思是超过这个值的时候,对象直接在old区分配内存 

    -XX:MaxTenuringThreshold (默认值为15) 年龄阈值 ,每个对象的前面都会有4个bit位的大小来存储他的年龄,最大为1111转为十进制就为15
  • 相关阅读:
    D3学习笔记一
    Python生成pyc文件
    Linux上用户之间对话
    uwsgi错误invalid request block size
    Nginx的Permission denied错误
    CentOS7关闭防火墙
    CentOS7.0安装Nginx
    应用IBatisNet+Castle进行项目的开发
    再论IBatisNet + Castle进行项目的开发
    DotNet软件开发框架
  • 原文地址:https://www.cnblogs.com/yjc1605961523/p/12419971.html
Copyright © 2020-2023  润新知