自动垃圾回收是Java相较于C++的一个重要的特点,想了解JVM的垃圾回收机制,首先我们要知道垃圾回收是回收什么地方的垃圾,我在我的上一篇博客《JVM内存区域划分》里面有写到JVM里面的内存是怎么分布的,这里的回收主要是指对上文中提到的Java堆和方法区的内存的回收。

什么样的对象可以被回收

知道了回收哪里的内存之后,我们还需要知道什么样的对象是可以被回收,或者说是需要被回收的,这些对象我们称之为死掉的对象。那么哪些对象是死掉了的呢?我们说当一个对象不存在任何引用的时候就可以说这个对象是死掉了。

那么什么时候这个对象不存在任何引用了呢?

有一些地方说,可以使用引用计数算法来判断对象是否还存活,引用计数算法是说给对象添加一个引用计数器,每当一个地方引用它时就加1,引用失效时就减1,计数器的值变为0就说这个对象不存在任何引用了,但是这样会存在一个很严重的问题,就是循环引用的问题。比如如下的例子:

public class Example{
public Object instance = null; public static void test(){
Example objA=new Example();
Example objB=new Example(); objA.instance=objB;
objB.instance=objA; objA=null;
objB=null;
}
}

这样的话,objA和objB的引用计数都不为0,但是他们的确是不会再被使用的了。

那么Java里面是用什么样的算法来实现对引用的判断的呢?

Java里是使用可达性分析的方法来实现的。

如图所示,就是通过一系列的称为"GC Roots"的对象作为起始点,从这些点向下搜索,搜索的路径称为引用链,当一个对象到达GC Roots没有任何引用链时,就可以证明这个对象是不可用的。那么这个对象就可以被回收了。像图中的Obj1-5都属于存活的对象,但是Obj6-8虽然还存在相互引用,但是已经是可以认为是死掉的对象了。

引用

目前来说,Java中的引用可以分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种,他们的引用顺序依次逐渐减弱。

  • 强引用是用来描述必须存在和引用的对象,比如Object a=new Object(),只要强引用还存在,被引用的对象就永远不会被回收。
  • 软引用是用来描述一些还有用但是不是必需的对象。这类引用的对象会在内存溢出之前被列入回收范围进行第二次回收,如若回收完之后还没有获得足够的内存才会抛出内存溢出异常。可以使用SoftReference类来实现。
  • 弱引用是用来描述非必需的对象,但是强度比软引用更弱,被引用的对象只能存活到下一次GC之前。当进行GC的时候不论内存是否足够都会对该引用的对象进行回收。可以使用WeakReference类来实现。
  • 虚引用是最弱的引用关系。虚引用的存在不会对对象的存活造成任何影响,也不能通过虚引用来获得任何对象实例。设置虚引用的唯一目的就是在关联对象被回收时会获得一个系统通知。可以使用PhantomReference类来实现。

死亡对象的自我救赎

当一个对象在进行可达性分析的时候发现已经是没有任何引用的了,这时候垃圾收集器并没有立即判处该对象死刑,而是给了它一次自我救赎的机会,这时它会被标记一次,同时判断是不是有必要执行finalize()方法,当对象没有重写finalize()方法或者finalize()方法已经被执行过的时候,就不执行finalize()方法。下面就会有两种情况发生了:

  • 执行finalize()方法:这时这个对象会被放在F-Queue队列之中,然后由虚拟机自动创建一个低优先级的Finalizer线程去执行它,但是为了保证F-Queue不被无限阻塞并不保证一定会等待finalize()方法执行结束。此时在finalize()里如果对象又重新获得与GC Roots的联系就可以完成自我救赎,否则的话就只能被第二次标记,然后听天由命了。
  • 不执行finalize()方法:这时候要么是垃圾收集器已经给过一次机会了,要么是对象自己没有重写finalize()去获得机会,这个时候就只能被第二次标记,立即被执行死刑了。

方法区的回收

方法区的回收分为废弃常量的回收和无用类的卸载。

  • 废弃常量的回收:回收废弃常量与上面所说的堆中对象的回收差不多,没有任何引用的时候回收。
  • 无用类的卸载:类的卸载需要满足三个条件:
  1. 该类的所有对象都被回收。
  2. 加载该类的ClassLoader已经被回收。
  3. 该类对应的java.lang.Class没有在任何地方被引用,无法在任何地方通过反射访问该类。

    但是满足这三个条件只是说可以被回收,但是不代表一定被回收,具体是否被回收还要由虚拟机里的一些参数来具体确定。

JVM内存回收对象及引用分析的更多相关文章

  1. JVM内存回收机制简述

    JVM内存回收机制涉及的知识点太多了,了解越多越迷糊,汗一个,这里仅简单做个笔记,主要参考<深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)> 目前java的jdk默认虚拟机为H ...

  2. JVM内存回收机制——哪些内存需要被回收(JVM学习系列2)

    上一篇文章中讨论了Java内存运行时的各个区域,其中程序计数器.虚拟机栈.本地方法栈随线程生灭,且创建时需要多少内存,基本上在译期间就决定的了,所以在内存回收时无需特殊的关注.而堆和方法区则不同,首先 ...

  3. Java基础-JVM内存回收

    Sun的JVMGenerationalCollecting(垃圾回收)原理是这样的:把对象分为年青代(Young).年老代(Tenured).持久代(Perm),对不同生命周期的对象使用不同的算法.( ...

  4. JVM内存回收机制

    1. JVM内存回收机制简述 http://www.cnblogs.com/lzrabbit/p/3826738.html

  5. K8S(18)容器环境下资源限制与jvm内存回收

    K8S(18)容器环境下资源限制与jvm内存回收 目录 K8S(18)容器环境下资源限制与jvm内存回收 一.k8s中的java资源限制与可能的问题 方案1:通过JVM的Xms和Xmx参数限制 方案2 ...

  6. JVM内存回收区域+对象存活的判断+引用类型+垃圾回收线程

    此文已由作者赵计刚薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 注意:本文主要参考自<深入理解Java虚拟机(第二版)> 说明:查看本文之前,推荐先知道JVM ...

  7. 第三章 JVM内存回收区域+对象存活的判断+引用类型+垃圾回收线程

    注意:本文主要参考自<深入理解Java虚拟机(第二版)> 说明:查看本文之前,推荐先知道JVM内存结构,见<第一章 JVM内存结构> 1.内存回收的区域 堆:这是GC的主要区域 ...

  8. JVM垃圾收集器&对象的引用回收

    1.介绍垃圾收集器 垃圾收集器(Garbage Collection,GC)就是用于回收方法区和堆区,其他程序计数器.虚拟机栈.本地方法栈这3个区域都是随线程而生,随线程而灭,栈中的栈帧会随着方法的进 ...

  9. JVM内存状况查看方法和分析工具

    Java本身提供了多种丰富的方法和工具来帮助开发人员查看和分析GC及JVM内存的状况,同时开源界和商业界也有一些工具可用于查看.分析GC及JVM内存的状况.通过这些分析,可以排查程序中内存泄露的问题及 ...

随机推荐

  1. JavaScript--声明提前

    声明提前(hoist): 在正式执行程序前,都会将所有var声明的变量和function声明的函数提前到*当前作用域*的顶部集中创建. 但是,赋值留在原地. console.log(a);//unde ...

  2. POJ2566-Bound Found (尺取法)

    POJ2566-Bound Found 题目大意:给出一段长度为n的数列,数列中的元素有正有负,求一段连续的区间,使得该区间的和的绝对值最接近给定的值 尺取法一般适用于对一段连续的区间的和进行处理的情 ...

  3. Reverse Interger

    Reverse digits of an integer. Example1: x = 123, return 321Example2: x = -123, return -321 Have you ...

  4. eval("("+json对象+")")

    var obj=eval("("+data+")"); 看看下面这条,应该能想到json的数据结构“+(json对象名)+”由于json是以”{}”的方式来开始 ...

  5. phalcon安装和输出 hello word

    1:下载和安装Wampserver2.4-x86.exe 服务器: 2:到phalcon官方网站下载对应的dll文件 phalcon_x86_VC9_php5.4.0_1.2.5 我下的是这个版本 所 ...

  6. 关于Python文档读取UTF-8编码文件问题

    近来接到一个小项目,读取目标文件中每一行url,并逐个请求url,拿到想要的数据. #-*- coding:utf-8 -*- class IpUrlManager(object): def __in ...

  7. [Struts2学习笔记] -- 简单的类型转换

    接下来学习一下Struts2简单的类型转换,Struts2基于ognl.jar实现了简单类型的数据转换.比如jsp页面中的form值与字段值的转换,下面写一个例子. 1.创建一个jsp页面,编写一个f ...

  8. Serilog with Autofac

    http://serilog.net/  ---不错的日志工具 1.直接绑定 builder.Register<ILogger>((c, p) => { return new Log ...

  9. codevs 1198 国王游戏

    传送门 题目描述 Description 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n位 ...

  10. linux c redirect 重定向

    用execvp实现时,运行adb,如果adb 服务没有启动,会启动adb服务,启动adb服务时,pipe返回的管道在读的时候堵塞了. 查看了popen的源码,发现popen是用sh -c来执行的,避免 ...