GC真正的垃圾:强、软、弱、和虚 对象
垃圾回收的基本思想就是判断一个对象是否可触及性,说白了就是判断一个对象是否可以访问,如果对象对引用了,说明对象正在被使用,如果发现对象没有被引用,说明对象已经不再使用了,不再使用的对象可以被回收,但是不一定立马被回收,取决于GC垃圾回收的算法。
判断对象的可触及性。
1.可以触及的:从根节点开始,可以到达这个对象,说明这个对象还在使用。
2.可复活的:对象的所有引用都被释放,但是对象可能在finalize()方法复活了。
3.不可触及的:对象的finalize()被调用,但是没有复活,那就彻底挂了,进入不可触及的状态。
不可触及的对象能复活吗?答案是不能,为啥,因为finalize()方法只会调用一次。
上面的三种情况只有不可触及的对象才可以被收回。
1.1. 对象的复活
对象的复活跟人的生老病死一样,在你临死的时候还有可能回光返照一次,如果成功了就复活了。所以想复活只抓住这一次机会,程序的回光返照就是finalize()方法,因为finalize()只会执行一次。
这里给出例子,演示这种情况,看下面的例子:
public class CanObj { public static CanObj canObj; @Override public String toString() { return " i am canObj"; } @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("finalize"); this.canObj=this; } public static void main(String[] args) throws Exception { canObj=new CanObj(); canObj=null; System.gc(); Thread.sleep(1000); if (canObj==null) { System.out.println("canObj null "); }else { System.out.println("canObj is not null"); } System.out.println("第二次GC"); canObj=null; System.gc(); Thread.sleep(1000); if (canObj==null) { System.out.println("canObj null "); }else { System.out.println("canObj is not null"); } } }
运行以上代码,输出如下:
finalize
canObj is not null
第二次GC
canObj null
说明确实触发finalize()方法了,而且只调用一次。
1.1.1. finalize说明
1.finalize()方法推荐不要使用
2.finalize()可能复活对象,可能发生引用外泄。
3.finalize()是系统调用的。所以调用时间是不确定的。所以资源的释放最好放在try catch finally中。
1.2. 引用和强、软、弱、和虚强度
java提供了四个级别的引用分别是强引用、软引用、弱引用和虚引用,强引用我们平时使用的就是比如new B()就是个强引用,其他的几种引用都可在在java.lang.ref.Reference找到他们的影子,如图显示了3中引用类型对应的类图关系,开发人员直接使用它们。
1.2.1. 强引用
强引用就是程序中一般的引用类型,强引用对象是可触及的,不会被回收,其他的几种就是在一定情况下是被回收的。
下面是一个强引用的例子:
StringBuffer str=new StringBuffer("hello shareniu");
上面的代码是在函数内可以运行的,那么局部变量str被分配在栈上,对象StringBuffer分配在堆上,局部变量str指向StringBuffer的堆空间,通过str可以操作实例,那么str就是StringBuffer实例的强引用如下图所示:
此时,在运行复制语句:
StringBuffer str1=str;
那么,str所指向的对象也将被str1指向,同事局部变量表也会存放str1的变量如下图所示:
System.out.println(str==str1);
相等的==比较的是操作数指向的堆空间的地址是否相等。
强引用特点如下:
1.强引用可以直接访问目标对象。
2.强引用对象任何时候都不会被系统回收,虚拟机抛出OOM异常也不会回收强引用对象。
3.强引用对象可能造成内存泄漏。
1.2.2. 软引用--可以被回收的引用
一个对象持有软引用,那么当堆空间不足的时候,就会回收这块区域。软引用实现类java.lang.ref.SoftReference<T>
下面演示软引用在系统堆内存不足的时候被回收。
public class SoftRef { public static class User{ private int id; private String name; public User(int id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } } public static void main(String[] args) { User user=new User(1, "shareniu"); SoftReference<User> usSoftReference=new SoftReference<SoftRef.User>(user); user=null; System.out.println(usSoftReference.get()); System.gc(); System.out.println("after gc"); System.out.println(usSoftReference.get()); byte []b=new byte[7*925*1024]; System.gc(); System.out.println(usSoftReference.get()); } }
配置参数-Xmx10m
分配10M内存所以堆空间内存不足的时候,软引用被回收。
程序输出如下:
User [id=1, name=shareniu](第一次从软引用获取到值)
after gc
User [id=1, name=shareniu](GC没有清除软引用,因为堆空间还有)
null(被清除了,因为堆空间慢了)
实验得出结论:GC不一定会回收软引用对象,但是内存不足的时候软引用会被回收,所以软引用对象不会OOM异常。
软引用的时候可以构造一个队列,当软引用对象被回收的时候,就会加入引用队列,通过对了可以追踪对象的回收情况。(在下面的通用例子中会降到)
1.2.3. 弱引用--发现即回收
在系统GC的时候,只要发现弱引用-不管系统堆内存是否使用,都会将对象进行回收,但是垃圾回收器的线程优先级比较低,所以不一定很快就能发现持有的弱引用对象。所以弱引用-可能存在比较长的时间。一旦一个弱引用-对象被回收,变回加入到注册的引用队列中
弱引用-具体的实现类java.lang.ref.WeakReference<T>
下面的例子显示弱引用的特点:
public class WakRef { public static class User{ private int id; private String name; public User(int id, String name) { this.id = id; this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } } public static void main(String[] args) { User user=new User(1, "shareniu"); WeakReference<User> weakReference=new WeakReference<WakRef.User>(user); user=null; System.out.println(weakReference.get()); System.gc(); System.out.println("after gc"); System.out.println(weakReference.get()); } }
程序输出如下:
User [id=1, name=shareniu]
after gc
null
可以看出,在GC之后,弱引用立即被清除了。
弱引用的时候可以构造一个队列,当弱引用对象被回收的时候,就会加入引用队列,通过对了可以追踪对象的回收情况。(在下面的通用例子中会降到)
1.2.4. 虚引用--对象回收追踪
虚引用是所有引用类型中最弱的一个,一个持有虚引用对象。和没有引用基本一样,随时都有可能被回收,当试图使用虚引用的get()获取的时候,总会失败报错,不能获取到。虚引用必须和引用队列一起使用,它的作用就是跟踪垃圾回收的过程。
当垃圾回收器回收一个对象的时候,如果发现他是虚引用,会立马讲这个虚引用的对象加入引用队列,通知应用程序对象的回收情况。所以我们在这里看一下队列如何使用。(除了强引用不能使用队列,其他的三个都可以使用,虚引用是必须使用队列)
下面给出一个实例,使用虚引用跟踪一个可以复活的对象的回收。
public class TraceObj { @Override public String toString() { return "TraceObj "; } public static TraceObj obj; //定义一个队列,对象回收时候会进入这个队列 static ReferenceQueue<TraceObj> queue=null; public static class CheckRefQuene extends Thread{ @Override public void run() { while (true) { if (queue!=null) { PhantomReference<TraceObj> phantomReference=null; try { phantomReference=(PhantomReference<TraceObj>) queue.remove(); } catch (InterruptedException e) { e.printStackTrace(); } if (phantomReference!=null) { System.out.println(" delete "+phantomReference); } } } } } @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("复活一个对象"); //复活一个对象 finalize只会执行一次 obj=this; } public static void main(String[] args) throws Exception { Thread thread=new CheckRefQuene(); thread.setDaemon(true); thread.start(); queue=new ReferenceQueue<TraceObj>(); obj=new TraceObj(); PhantomReference<TraceObj> phantomReference=new PhantomReference<TraceObj>(obj, queue); obj=null; System.gc(); Thread.sleep(1000); if (obj==null) { System.out.println("null "); }else { System.out.println("obj is not null "); } System.out.println("第二次gc"); obj=null; System.gc(); Thread.sleep(1000); if (obj==null) { System.out.println("null "); }else { System.out.println("obj is not null "); } } }
程序的输出如下:
复活一个对象
obj is not null
第二次gc
delete java.lang.ref.PhantomReference@1d86fd3 (删除的对象确实进入队列了)
null
虚引用对象可以跟踪对象的回收时间,所以,可以将一些资源释放操作放在虚引用中执行和记录。
1.2.5. 比较
软、弱、和虚 引用都可以放置到队列中,强引用不需要,虚引用必须要使用队列。
软引用可以放一些缓存的数据,当内存不足的时候被回收
软引用在设备内存比较少的时候特别有用,比如android系统。
一个android应用如果设计到通过网络获取图片,为了让系统更快的运行和更节省流量我们可以将已经下载下来的图片缓存起来,当第二次浏览到该图片时就可以从缓存中拿。
缓存的方式有:一是放在系统内存中这样效率最高,二是把文件写到外部存储器上。但是就目前而言android系统的内存是非常的有限的不可能像PC机那样配置那么高的内存,而且外部存储器的容量也是有限的。
如何我们用SoftReference的方式存储在内存中是一中很好的解决方法(当然不止这一种)。
虚引用对象可以跟踪对象的回收时间,所以,可以将一些资源释放操作放在虚引用中执行和记录。
GC真正的垃圾:强、软、弱、和虚 对象的更多相关文章
- java中强,软,弱,虚引用 以及WeakHahMap
java中强,软,弱,虚引用 以及WeakHahMap 一:强软引用: 参考:http://zhangjunhd.blog.51cto.com/113473/53092/进行分析 packa ...
- java中的强,软,弱,虚引用
引用的应用场景 我们都知道垃圾回收器会回收符合回收条件的对象的内存,但并不是所有的程序员都知道回收条件取决于指向该对象的引用类型.这正是Java中弱引用和软引用的主要区别. 如果一个对象只有弱引用指向 ...
- [翻译] 编写高性能 .NET 代码--第二章 GC -- 减少大对象堆的碎片,在某些情况下强制执行完整GC,按需压缩大对象堆,在GC前收到消息通知,使用弱引用缓存对象
减少大对象堆的碎片 如果不能完全避免大对象堆的分配,则要尽量避免碎片化. 对于LOH不小心就会有无限增长,但LOH使用的空闲列表机制可以减轻增长的影响.利用这个空闲列表,我们可以在两块分配区域中间找到 ...
- JVM-gcRoots 和 强引用,软引用, 弱引用, 虚引用, 代码演示和应用场景
什么是垃圾? 什么是gcRoots, 谈谈你对 强, 软, 弱 , 虚引用的理解, 他们的应用场景 jvm采用可达性分析法: 从gcRoots集合开始,自上向下遍历,凡是在引用链上的对象,都不是垃圾, ...
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
- Java:对象的强、软、弱、虚引用
转自: http://zhangjunhd.blog.51cto.com/113473/53092 1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无 ...
- 【转载】 Java 7之基础 - 强引用、弱引用、软引用、虚引用
原文地址:http://blog.csdn.net/mazhimazh/article/details/19752475 1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一 ...
- Java中四种引用:强、软、弱、虚引用
这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...
- Java:对象的强、软、弱和虚引用
1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK ...
随机推荐
- 【BZOJ1835】【ZJOI2010】基站选址
原题传送门 Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距 ...
- 【CODEVS 6384 大米兔学全排列】
·大米兔学习全排列,还有一些逆序对,还有一棵二叉索引树.· ·分析: 首先肯定不是像题目上说的那样,使用next_permutation去完成这道题,因为就算是线性的它也不能承受庞大的排列 ...
- [BZOJ]1050 旅行comf(HAOI2006)
图论一直是小C的弱项,相比其它题型,图论的花样通常会更多一点,套路也更难捉摸. Description 给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权 ...
- JS 实现点击页面任意位置隐藏div、span
通过调用下面的 showhidden(“标签ID”) 显示div/span/…等标签内容,可以实现点击页面任意地方再次隐藏该标签内容,而showhidden(“标签ID”,”nohidden”)可保存 ...
- SSD:TensorFlow中的单次多重检测器
SSD:TensorFlow中的单次多重检测器 SSD Notebook 包含 SSD TensorFlow 的最小示例. 很快,就检测出了两个主要步骤:在图像上运行SSD网络,并使用通用算法(top ...
- Gethub readme 撰写
大标题=== 小标题----- #一级标题 ##二级标题 ###三级标题 ####四级标题 #####五级标题 ######六级标题 插入圆点* 昵称:果冻虾仁 * 别名:隔壁老王 * 英文名:Jel ...
- WEB中间件--tomcat爆破,burp和python脚本
1.tomcat 用burpsuit进行弱口令爆破 先抓包 发送到inturder payload type 选择custom iterater 第一个payload选用户名文件,第二个payload ...
- Safari 3D transform变换z-index层级渲染异常
(猛戳来源:http://www.zhangxinxu.com/wordpress/?p=5569)
- Struts+Hibernate+jsp页面,实现分页
dao层代码 package com.hanqi.dao; import java.util.ArrayList; import java.util.List; import org.hibernat ...
- React框架 dva 和 mobx 的使用感受
最近在用react写web项目,领导为了让前端便于维护要求都用react作为开发基础,框架选型不限.在使用 react 的时候或多或少会接触到状态管理,从开始学 react 到现在也挺久了,做一些前端 ...