zoukankan      html  css  js  c++  java
  • 垃圾回收机制

    java堆中存放的是java对象:
    当GC回收之前会判断对象的状态,判断这些对象那些还存活,那些已经“死去

    如何判断对象的状态?
    引用计数法:给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已“死”。
    在主流的JVM中没有选用引用计数法来管理内存,最主要的原因是引用计数法无法解决对象的循环引用问题。

    可达性分析算法:通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为“引用链”,当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用
    (别人家图,狗头保命)

    可作为GC Roots的对象包含以下几种:

    1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。
      2.方法区中静态属性引用的对象
      3.方法区中常量引用的对象
      4.本地方法栈中(Native方法)引用的对象

    java的引用
    强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)四种,这四种引用的强度依次递减。
    GC对于这四种引用的处理
    强引用(Strong Reference): 强引用指的是在程序代码之中普遍存在的,类似于"Object obj = new Object()"这类的引用,只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象实例。
    软引用(Soft Reference):内存溢出之前,会把这些对象列入回收范围之中进行第二次回收。如果这次回收还是没有足够的内存,才会抛出内存溢出异常
    弱引用(Weak Reference):只能生存到下一次垃圾回收发生之前
    虚引用(Phantom Reference):一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,这个对象被收集器回收时收到一个系统通知

    可达性分析算法的特点:
    如果对象在进行可达性分析之后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法或者finalize()方法已经被JVM调用过,虚拟机会将这两种情况都视为"没有必要执行",此时的对象才是真正"死"的对象。
    如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个叫做F-Queue的队列之中,并在稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行它(这里所说的执行指的是虚拟机会触发finalize()方法)。finalize()方法是对象逃脱死亡的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象在finalize()中成功拯救自己(只需要重新与引用链上的任何一个对象建立起关联关系即可),那在第二次标记时它将会被移除出"即将回收"的集合;如果对象这时候还是没有逃脱,那基本上它就是真的被回收了。

    回收方法区
    方法区(永久代)的垃圾回收主要收集两部分内容:废弃常量和无用类。
    回收废弃常量:当前系统没有任何一个对象引用常量池中的常量,也没有其他地方引用这个字面量,如果此时发生GC并且有必要的话,这个常量会被系统清理出常量池
    回收无用类
    1.该类的所有实例都已经被回收(即在Java堆中不存在任何该类的实例)
    2.加载该类的ClassLoader已被回收
    3.该类对应的Class对象没有任何其他地方被引用,无法在任何地方通过反射访问该类的方法

    垃圾回收算法
    ** 标记-清除算法**:
    算法分为标记和清除两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象(可达性分析)
    弊端:
    1.标记和清除这两个过程的效率都不高
    2.空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。

    复制算法(新生代算法)
    将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。这样做的好处是每次都是对整个半区进行内存回收,内存分配时也就不需要考虑内存碎片等的复杂情况,只需要移动堆顶指针,按顺序分配即可。

    空间的划分
    Eden(伊甸园)、Survivor(from/to)空间 8:1:1

    复制算法流程:
    1.当Eden区满的时候,会触发第一次Minor gc,把还活着的对象拷贝到Survivor From区
    2.当Eden区再次出发Minor gc的时候,会扫描Eden区和From区,对两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到To区域,并将Eden区和From区清空
    3.当后续Eden区又发生Minor gc的时候,会对Eden区和To区进行垃圾回收,存活的对象复制到From区,并将Eden区和To区清空
    4.部分对象会在From区域和To区域中复制来复制去,如此交换15次(由JVM参数MaxTenuringThreshold决定,这个参数默认是15),最终如果还存活,就存入老年代。

    标记-整理算法(老年代回收算法)
    标记过程仍与“标记-清除”过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象向一端移动,然后直接清理掉端边界以外的内存

    分代收集算法
    只是根据对象存活周期的不同将内存划分为几块。

    金麟岂能忍一世平凡 飞上了青天 天下还依然
  • 相关阅读:
    socket套接字 struct模块
    网络编程 OSI七层协议
    内置方法 eval | exec 元类 单例
    选课系统
    iOS清理缓存 2016-04-19
    iOS 蓝牙 技术
    iOS人脸识别
    iOS 指纹识别
    极光推送的初步配置及其使用
    iOS 加急审核
  • 原文地址:https://www.cnblogs.com/Auge/p/14303853.html
Copyright © 2011-2022 走看看