1.介绍垃圾收集器

 垃圾收集器(Garbage Collection,GC)就是用于回收方法区和堆区,其他程序计数器、虚拟机栈、本地方法栈这3个区域都是随线程而生,随线程而灭,栈中的栈帧会随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。每一个栈帧中分配多少内存在类结构确定下来时就是已知的,因此这几个区域的内存分配和回收都是具备确定性,所以这3个区域不需要考虑回收,因为方法结束或线程结束时,内存自然就跟着回收了。而Java堆和方法区就不同,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序出于运行期间才能知道会创建那些对象,这部分内存分配和回收都是动态的,所以这是垃圾收集器关注的内存。 

1.1如何判定对象是否存活?

引用计数算法

  给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0 的对象就是不能在被使用的。这种算法的优点在于判定效率高,实现简单,但Java 虚拟机没有选用引用计数算法来管理内存,原因是它很难解决相互循环引用的问题。

下面的代码可以看出两个对象互相引用对方的属性所以不会被GC

public class ReferenceCountingGc {
public Object instance = null;
private int _1MB = 1024*1024;
private byte[] bigSize = new byte[2 * _1MB]; public static void testGC() {
ReferenceCountingGc objA = new ReferenceCountingGc();
ReferenceCountingGc objB = new ReferenceCountingGc();
objA.instance = objB;
objB.instance = objA; objA = null;
objB = null; System.gc();
}
public static void main(String[] args) {
ReferenceCountingGc.testGC();
}
}

可达性分析算法

主流商用程序语言(JAVA 、C#)的主流实现都是通过可达性分析来判定对象是否存活。基本思路就是通过一些列的成为“GC Roots”的对象作为起始点,从这些结点开始向下搜索,搜索所走过的路径成为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连时,则证明对象是不可用的。

在 Java 语言中,可作为GC Roots的对象包括下面几种:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中 JNI(Native方法) 引用的对象

2.对象的引用

  无论是引用计数器判断对象的引用数量,还是可达性分析算法判断引用链是否可达,判定对象是否存活都与“引用”有关。JDK1.2 以前,Java 中引用的定义为 如果 reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表这一个引用。一个对象只有引用或者未被引用两种状态,总感觉缺少点什么,我们希望能描述这样一类对象:当内存还足够时,则能保留内存之中;如果内存空间在进行GC后还非常紧张,则可以抛弃这些对象。

所以在JDK1.2 之后,Java 对引用概念进行扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)。

  • 强引用:类似“Object obj = new Object()”只要强引用还存在,垃圾收集器永远不会回收掉被应用的对象
  • 软引用:用来描述一些还有用但并非必须的对象。对于软引用关联的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才回抛出内存溢出异常->JDK1.2后,提供了SoftReference类来实现软引用
  • 弱引用:用来描述非必须对象的,强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集器发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象->JDK1.2后,提供了WeakReference类来实现弱引用
  • 虚引用:称为幽灵引用或幻影引用,它是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。一个对象关联虚拟引用唯一目地就是能在这个对象被收集器回收时收到一个通知->PhantomReference来实现虚引用

用法如下

public class Test {
User u = new User();
SoftReference s = new SoftReference(u);
WeakReference w = new WeakReference(u);
PhantomReference p = new PhantomReference(u, null);
}

2.1对象的缓刑

  并不是在可达性分析算法中被标记一次就会马上被回收,而是至少要经历两次标记过程:如果对象在进行可达性分析后没有与GC Roots 相连接的引用链,则会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行的 finalize()方法。当对象没有覆盖 finalize()方法,或 finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。

如果这个对象被判定没必要执行 finalize()方法,这个对象将会放置在F-Queue的队列中,并稍后由虚拟机自动建立的、低优先级的 Finalizer 线程去执行它。这里“执行”是虚拟机会触发这个方法,并不承诺会等待它运行结束,如果在对象的finalize()方法中执行缓慢,或者发生死循环,会导致F-Queue 队列其他对象永久处于等待,会导致内存回收系统崩溃。finalize()方法是对象逃脱回收的最后一次机会,稍后GC 将对 F-Queue中的对象进行第二次小规模标记,如果对象在finalize()中重新与引用链上任何一个对象建立关联即可,如把自己(this)赋值给某个类变量或者对象的成员变量,第二次标记时就会将它移除“即将回收”的集合;如果对象此时还没逃脱基本就被回收了。

注意:finalize()方法只会被系统自动调用一次

2.1回收方法区

  垃圾收集器主要回收两部分内容:废弃常量和无用的类废弃常量如字符串“abc”已经进入常量池中,但没有任何一个String对象引用它,也没有其他地方引用这个字面量,如果发生内存回收,而且有必要的话,这个“abc”常量就会被系统清理出常量池

无用的类需要同时满足已下3个条件才算。

  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例
  • 加载该类的ClassLoader已经被回收
  • 该类java.lang.Class 对象没有任何地被引用,无法在任何地方通过反射访问该类的方法

JVM垃圾收集器&对象的引用回收的更多相关文章

  1. JVM之垃圾收集器与内存分配回收策略(二)

    上一篇JVM垃圾收集器与内存分配策略(一),下面是jdk1.7版本的垃圾收集器之间的关系,其中连线两端的两种垃圾收集器可以进行搭配使用,下面来总结一下这些收集器的一些特点以及关系. 一.Serial收 ...

  2. 第五章 JVM垃圾收集器(1)

    说明:垃圾回收算法是理论,垃圾收集器是回收算法的实现,关于回收算法,见<第四章 JVM垃圾回收算法> 1.七种垃圾收集器 Serial(串行GC)-- 复制 ParNew(并行GC)-- ...

  3. 第六章 JVM垃圾收集器(2)

    上一章记录了几种常见的垃圾收集器,见<第五章 JVM垃圾收集器(1)> 1.G1 说明: 从上图来看,G1与CMS相比,仅在最后的"筛选回收"部分不同(CMS是并发清除 ...

  4. JVM垃圾收集器(1)

    此文已由作者赵计刚薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 说明:垃圾回收算法是理论,垃圾收集器是回收算法的实现,关于回收算法,见<第四章 JVM垃圾回收算法& ...

  5. 5种JVM垃圾收集器特点和8种JVM内存溢出原因

    先来看看5种JVM垃圾收集器特点 一.常见垃圾收集器 现在常见的垃圾收集器有如下几种: 新生代收集器: Serial ParNew Parallel Scavenge 老年代收集器: Serial O ...

  6. 7种 JVM 垃圾收集器特点、优劣势及使用场景(多图)

    7种 JVM 垃圾收集器特点.优劣势及使用场景(多图)  mp.weixin.qq.com 点击上方"IT牧场",选择"设为星标"技术干货每日送达! 一.常见垃 ...

  7. 深入理解JVM - 垃圾收集器

    垃圾回收主要是要解决3件事情: 那些内存需要回收? 如何回收? 什么时候回收? 那些内存需要回收 在强引用的情况下已经“死”了的对象就需要回收,在非强引用的情况下视情况回收.在java里面,几乎所有的 ...

  8. JVM垃圾收集器-Parallel Scavenge收集器

    今天我给大家讲讲JVM垃圾收集器-Parallel Scavenge收集器 Parallel Scavenge收集器 Parallel Scavenge收集器也是一个新生代收集器,它也是使用复制算法的 ...

  9. 7种JVM垃圾收集器特点,优劣势、及使用场景

    今天继续JVM的垃圾回收器详解,如果说垃圾收集算法是JVM内存回收的方法论,那么垃圾收集器就是内存回收的具体实现. 一.常见的垃圾收集器有3类 1.新生代的收集器包括 Serial PraNew Pa ...

随机推荐

  1. 权限认证 cookie VS token

    权限认证 cookie VS token 我前公司的应用都是 token 授权的,现公司都是维护一个 session 确认登录状态的.那么我在这掰扯掰扯这两种权限认证的方方面面. 工作流程 先说 co ...

  2. Maven中解决依赖冲突的问题

    1.短路优先:谁离得最近就使用谁的依赖jar包 C到达A为C->B->A C到达B为C->B 例如: A中的 commons-io的版本为2.4 B中的commons-io的版本为2 ...

  3. php的内置函数debug_backtrace()与get_included_files()跟踪代码调用(Thinkphp框架举例)

    debug_backtrace() 在我们开发一个项目中,或者二开研究某个开源程序,需要对代码流程一步步去跟踪,来研究它的逻辑,才可以进行修改,达到我们的开发目的.php的内置函数debug_back ...

  4. TP5整合 WorkerMan 以及 GatewayWorker

    TP5整合GatewayWorker Windows版安装 a)使用composer create-project topthink/think testTG,来安装thinkphp5. b)进入t ...

  5. (MonoGame从入门到放弃-2) 初识MonoGame

    上一节记录了大致的搭建MonoGame的环境,默认大家都是都是使用过Visual Studio的,没使用过的话,可以去https://www.visualstudio.com/下载一个试试,社区版免费 ...

  6. Centos下的GitLab的安装汉化和数据备份以及管理员密码重置

    前言: 安装版本:gitlab-ce-8.8.5-ce.1.el7.x86_64.rpm 下载地址: https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yu ...

  7. Python 关于super 的 用法和原理(挖坑)

    一.前言 Python 面向对象中有继承这个概念,初学时感觉很牛逼,里面也有个super类,经常见到,最近做一些题才算是理解了.特地记录分享给后来研究的小伙伴,毕竟现在小学生都开始学了(滑稽脸) 二. ...

  8. 《Java编程思想》读书笔记

    前言 这个月一直没更新,就是一直在读这本<Java编程思想>,这本书可以在Java业界被传神的一本书,无论谁谈起这本书都说好,不管这个人是否真的读过这本书,都说啊,这本书很好.然后再看这边 ...

  9. 对ios、android开发程序员的14条忠告

    ————————本文摘自千锋教育(http://www.mobiletrain.org/)对ios\android开发程序员的14条忠告————————— 1.不要害怕在工作中学习. 只要有电脑,就可 ...

  10. mysql数据库 调优

    mysql调优硬件配置网络带宽mysql运行参数慢查询日志网络架构多实例(一台服务器上运行多个数据库服务)分库分表 当一台数据库服务器处理客户端的请求慢时,可能是哪些原因造成? 硬件配置低:(内存 c ...