• JVM垃圾收集


    一.jvm判断对象是否已死的方法

    1.引用计数法,缺陷-很难解决对象之间相互循环引用的问题。

    2.根搜索算法,通过一系列的名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所经过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

    在java中,GC Roots的对象包括下面几种:

    1.虚拟机栈(栈帧中的本地变量表)中引用的对象

    2.方法区中的类静态属性引用的对象

    3.方法区中常量引用的对象

    4.本地方法栈中JNI(也就是Native方法)的引用的对象

    以上两种判断对象是否已死的方法都和引用有关系,在jdk1.2之前,引用的定义就是如果reference类型的数据中存储的数值代表的是另外一个内存的起始地址,就称这块内存代表着一个引用。这显得太

    过狭隘,所以在jdk1.2之后呢,对于引用的概念进行了扩充:

    1.强引用:类似"Object obj = new Object()"这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。

    2.软引用(SoftReference):用来描述一些还在用,但并非必须的对象。对于软引用关联的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中并进行第二次回收(也就是说如果这

    个对象在第二次引用时还没有逃离就会被回收),如果这次回收还是没有足够的内存,才会抛出内存溢出异常。

    3.弱引用(WeakReference):被弱引用关联的对象只能生存到下一次垃圾收集发生之前。

    4.虚引用(PhantomReference):一个对象是否有虚引用的存在,完全不会对其生存构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用的目的就是希望能在这个对象被回收时收到一个通知。

    二.生存还是死亡?

    在根搜索算法中不可达的对象,也并非是非死不可的,这时候他们暂时处于"缓刑"阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行根搜索后发现没有与GC Roots相连的引用链,那它将会第一次被标记并且进行一次筛选,筛选的条件的是此对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为"没有必要执行"。

    如果这个对象被判定为有必要执行finalize()方法,那么这个对象会被放置在一个F-Queue队列中,然后由一条虚拟机自动建立,低优先级的finalizer线程去执行。这里所谓的执行是指虚拟机会触发这个方法,但并不承诺会等待它运行结束。这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环,将很可能会导致F-Queue队列中的其他对象永久处于等待状态,设置导致整个内存回收系统崩溃。

    finalize()方法是对象逃脱死亡的最后一次机会,稍后GC将对F-Queue队列中的对象进行第二次小规模的标记,如果对象在finalize()方法中成功拯救自己,那么将在第二次标记时它将被移除'即将回收'的集合。如果对象还是没有逃脱,那么离死不远了。

    三.回收方法区

    在方法区中实现垃圾收集的性价比很低- 在堆中,尤其是新生代中,常规应用进行一次垃圾收集一般可以回收70%-95%的空间,而在永久代远低于此。
    永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类
    1.废弃常量的回收方式和堆中的对象非常类似。就是没有任何对象引用常量池中的某个常量,也没有其他地方引用这个常量,那么就回收。如果必要的话,这个常量就会被系统“请”出常量池。
    2.判定无用的类需要满足3个条件:
    该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
    加载该类的classloader已经被回收
    该类对应的java.lang.class对象没有在任何地方被引用,无法在任何地方通过反射访问该类。

    四.垃圾收集算法

    1.标记-清除算法
    缺点:效率不高,空间有浪费(产生大量不连续的空间碎片)

    2.复制算法
    回收新生代,因为新生代基本上都是朝生夕灭的,所以不需要按照1:1的比例来划分内存空间,而是将内存分为一个较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块survicor。当回收时,将Eden和survicor还存活的对象一次性拷贝到另一块survivor空间上,最后清理掉Eden和刚才使用的survicor的空间。hotspot虚拟机的默认eden和survivor的大小比例是8:1。

    3.标记-整理算法

    4.分代收集算法 - 新生代用复制算法。老年代用标记算法

    五.垃圾收集器

     上图中连线的表示相互之间可以配合使用

    1.Serial收集器(新生代收集器) - 单线程的收集器,在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。但是也有些优点,比如简单而高效(与其他收集器的单线程比)
    2.ParNew收集器(新生代收集器) - 其实就是Serial收集器的多线程版本,除了Serial收集器外,目前只有它能与CMS收集器配合工作。
    3.Parallel Scavenge收集器(新生代收集器) - 和Parnew不同之处是,它的目标则是达到一个可控制的吞吐量。
    4.Serial Old收集器 - Serial收集器的老年代版本
    5.Parallel Old收集器 - Parallel Scavenge收集器的老年代版本
    6.CMS收集器 - 一种以获取最短回收停顿时间为目标的收集器,重视服务器响应速度。用标记清除算法
    7.G1收集器 - 基于标记整理算法实现的收集器;另外它可以非常精确的控制停顿

    下面是垃圾收集器的常用参数

  • 相关阅读:
    查询详细信息和删除记录
    软件开发过程中常用到的一些工具
    无服务器端的UDP群聊功能剖析(WCF版)
    vim插件使用
    C#中ConnectionStrings和AppSettings的区别
    《Effective C++》简明笔记上
    设计模式的一些所想所得
    对RESTful Web API的理解与设计思路
    js加载脚
    OSGi.NET 学习笔记 [模块可扩展支持][概念][实例]
  • 原文地址:https://www.cnblogs.com/juin1058/p/11718774.html
Copyright © 2020-2023  润新知