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 ...
随机推荐
- 高可用之KeepAlived(一):基本概念和配置文件分析
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
- 手把手教你用.NET Core写爬虫
写在前面 自从上一个项目58HouseSearch从.NET迁移到.NET core之后,磕磕碰碰磨蹭了一个月才正式上线到新版本. 然后最近又开了个新坑,搞了个Dy2018Crawler用来爬dy20 ...
- PHP如何防止XSS攻击
PHP防止XSS跨站脚本攻击的方法:是针对非法的HTML代码包括单双引号等,使用htmlspecialchars()函数 . 在使用htmlspecialchars()函数的时候注意第二个参数, 直接 ...
- the c programing language 学习过程4
4Functions and Program Structure scratch 刮擦 starting over from scratch从头开始 reside驻留 separately 分别的 f ...
- UVA - 11995 I Can Guess the Data Structure!(模拟)
思路:分别定义栈,队列,优先队列(数值大的优先级越高).每次放入的时候,就往分别向三个数据结构中加入这个数:每次取出的时候就检查这个数是否与三个数据结构的第一个数(栈顶,队首),不相等就排除这个数据结 ...
- 计蒜客 无脑博士 bfs
题目链接无脑博士的试管们 思路:直接模拟倒水过程即可,但是需要记忆判断当前的情况是否已经处理过.dfs和bfs都ok AC代码 #include <cstdio> #include < ...
- Spring MVC处理(下周完善)
http://www.cnblogs.com/xiepeixing/p/4244574.html http://blog.csdn.net/kobejayandy/article/details/12 ...
- mysql字符设置
MySQL字符集设置 mysql>CREATE DATABASE IF NOT EXISTS mydb default charset utf8 COLLATE utf8_general_ci; ...
- 阻止微信浏览器/QQ浏览器长按弹框“在浏览器打开”
这个弹框实际上等同于PC环境下的鼠标右键的弹框,因此只要禁止页面的弹框事件就能完美屏蔽该弹框对我们功能带来的影响.程序代码如下: document.oncontextmenu=function(e){ ...
- Linux分区和挂载(mount命令的学习)
当Windows系统出现问题的时候,可能需要重装系统,这个时候我们往往会使用系统盘将系统重新安装在C盘上,其他盘上的文件都没有受到重装系统的影 响,这就是分区的好处之一.同样,在Linux中也需要分区 ...