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. asp.net core 使用 swagger 生成接口文档

    参考地址:http://www.cnblogs.com/daxnet/p/6181366.html http://www.jianshu.com/p/fa5a9b76f3ed 微软参考文档:https ...

  2. 对于ArrayList中的泛型进行分析

    package cn.lonecloud.reflect; import java.lang.reflect.Method; import java.util.ArrayList; public cl ...

  3. 微博爬虫“免登录”技巧详解及 Java 实现(业余草的博客)

    一.微博一定要登录才能抓取? 目前,对于微博的爬虫,大部分是基于模拟微博账号登录的方式实现的,这种方式如果真的运营起来,实际上是一件非常头疼痛苦的事,你可能每天都过得提心吊胆,生怕新浪爸爸把你的那些账 ...

  4. c++ 如何获取多线程的返回值?

    // Console.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <stdlib.h> #include ...

  5. mysql 学习心得2

    1tinyint small~ medium~ int big~ float double dec(M,D)定点数 取值范围由md确定 bit(M)位类型 bit(1) bit(64). 2zerof ...

  6. hihoCoder 1523 数组重排2 贪心

    题意:给定一个1-N的排列A1, A2, - AN,每次操作小Hi可以选择一个数,把它放到数组的最左边. 请计算小Hi最少进行几次操作就能使得新数组是递增排列的. 思路:最后的序列是递增的,那么必定满 ...

  7. UVA-12166 天平性质+字符处理

    这题思维难度很大,关键是总结这个性质. 1.天平性质:某个秤砣重量为w,高度为h,如果要让这个天平平衡并且以这个秤砣为基准,那么整个天平的总重量为w*(2^h) 2.利用这个性质:题目要求秤砣数量改变 ...

  8. 吾八哥学Selenium(二):操作输入框/按钮的方法

    一个web页面一定少不了输入框或者按钮这两种元素,那么在Python里如何使用Selenium操作web页面里的输入框和按钮呢?本文带你简单入门. 本文采用了一个例子,就是利用Selenium打开百度 ...

  9. gogogo

  10. Jetty添加Filter过滤器

    1.Jetty嵌入到Spring项目 try { Server server = new Server(8080); WebAppContext context = new WebAppContext ...