JVM垃圾收集器&对象的引用回收
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垃圾收集器&对象的引用回收的更多相关文章
- JVM之垃圾收集器与内存分配回收策略(二)
上一篇JVM垃圾收集器与内存分配策略(一),下面是jdk1.7版本的垃圾收集器之间的关系,其中连线两端的两种垃圾收集器可以进行搭配使用,下面来总结一下这些收集器的一些特点以及关系. 一.Serial收 ...
- 第五章 JVM垃圾收集器(1)
说明:垃圾回收算法是理论,垃圾收集器是回收算法的实现,关于回收算法,见<第四章 JVM垃圾回收算法> 1.七种垃圾收集器 Serial(串行GC)-- 复制 ParNew(并行GC)-- ...
- 第六章 JVM垃圾收集器(2)
上一章记录了几种常见的垃圾收集器,见<第五章 JVM垃圾收集器(1)> 1.G1 说明: 从上图来看,G1与CMS相比,仅在最后的"筛选回收"部分不同(CMS是并发清除 ...
- JVM垃圾收集器(1)
此文已由作者赵计刚薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 说明:垃圾回收算法是理论,垃圾收集器是回收算法的实现,关于回收算法,见<第四章 JVM垃圾回收算法& ...
- 5种JVM垃圾收集器特点和8种JVM内存溢出原因
先来看看5种JVM垃圾收集器特点 一.常见垃圾收集器 现在常见的垃圾收集器有如下几种: 新生代收集器: Serial ParNew Parallel Scavenge 老年代收集器: Serial O ...
- 7种 JVM 垃圾收集器特点、优劣势及使用场景(多图)
7种 JVM 垃圾收集器特点.优劣势及使用场景(多图) mp.weixin.qq.com 点击上方"IT牧场",选择"设为星标"技术干货每日送达! 一.常见垃 ...
- 深入理解JVM - 垃圾收集器
垃圾回收主要是要解决3件事情: 那些内存需要回收? 如何回收? 什么时候回收? 那些内存需要回收 在强引用的情况下已经“死”了的对象就需要回收,在非强引用的情况下视情况回收.在java里面,几乎所有的 ...
- JVM垃圾收集器-Parallel Scavenge收集器
今天我给大家讲讲JVM垃圾收集器-Parallel Scavenge收集器 Parallel Scavenge收集器 Parallel Scavenge收集器也是一个新生代收集器,它也是使用复制算法的 ...
- 7种JVM垃圾收集器特点,优劣势、及使用场景
今天继续JVM的垃圾回收器详解,如果说垃圾收集算法是JVM内存回收的方法论,那么垃圾收集器就是内存回收的具体实现. 一.常见的垃圾收集器有3类 1.新生代的收集器包括 Serial PraNew Pa ...
随机推荐
- ASP.NET Core的身份认证框架IdentityServer4--(1)服务配置
官网文档地址:点我点我 准备 创建一个名为IdentityServer的ASP.NET Core Web Api 项目,端口5000 创建一个名为Api的ASP.NET Core Web Api 项目 ...
- maven中的传递依赖和传递依赖的解除
例如创建三个maven工程A B C pom文件分别为 A <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns: ...
- 利用Apache配置本地 自定义域名
第一步:配置 httpd.conf 开启 虚拟主机 配置模块 去掉 " Include conf/extra/httpd-vhosts.conf " 前面的" # &qu ...
- HttpURLConnection 411错误解决
1.问题描述 Java HttpURLConnection类发送Http请求链接外网返回ResponseCode为411,对方为.NET服务器,网上查明原因可能来自以下: 1.可能是没有传http中的 ...
- sqoop:mysql和Hbase/Hive/Hdfs之间相互导入数据
1.安装sqoop 请参考http://www.cnblogs.com/Richardzhu/p/3322635.html 增加了SQOOP_HOME相关环境变量:source ~/.bashrc ...
- 使用tcpcopy导入线上流量进行功能和压力测试
- 假设我们要上线一个两年内不会宕机的先进架构.在上线前,免不了单元测试,功能测试,还有使用ab,webbench等等进行压力测试. 但这些步骤非生产环境下正式用户的行为.或许你会想到灰度上线,但毕竟 ...
- qwe框架- CNN 实现
CNN实现 概述 我在qwe中有两种,第一种是按照Ng课程中的写法,多层循环嵌套得到每次的"小方格",然后WX+b,这样的做法是最简单,直观.但是效率极其慢.基本跑个10张以内图片 ...
- 分析Android-Universal-Image-Loader的缓存处理机制
最近看了UIL中的缓存实现,才发现其实这个东西不难,没有太多的进程调度,没有各种内存读取控制机制.没有各种异常处理.反正UIL中不单代码写的简单,连处理都简单.但是这个类库这么好用,又有这么多人用,那 ...
- plx9030触发pci中断
if(((SWAB_16(PLX_INT(0x4C)))&0x04)==0x04) { ErrNo = *(UINT16*)(g_MemBase+0XFFFE*2); /*logMsg(&qu ...
- 【linux】 LINUX FTP搭建
1.安装ftp服务 yum install vsftpd 2.编辑配置文件 vsftpd的配置文件有三个,分别是:/etc/vsftpd/vsftpd.conf/etc/vsftpd/ftpusers ...