垃圾回收的基本思想就是判断一个对象是否可触及性,说白了就是判断一个对象是否可以访问,如果对象对引用了,说明对象正在被使用,如果发现对象没有被引用,说明对象已经不再使用了,不再使用的对象可以被回收,但是不一定立马被回收,取决于GC垃圾回收的算法。

判断对象的可触及性。

1.可以触及的:从根节点开始,可以到达这个对象,说明这个对象还在使用。

2.可复活的:对象的所有引用都被释放,但是对象可能在finalize()方法复活了。

3.不可触及的:对象的finalize()被调用,但是没有复活,那就彻底挂了,进入不可触及的状态。

不可触及的对象能复活吗?答案是不能,为啥,因为finalize()方法只会调用一次。

上面的三种情况只有不可触及的对象才可以被收回。

1.1. 对象的复活

对象的复活跟人的生老病死一样,在你临死的时候还有可能回光返照一次,如果成功了就复活了。所以想复活只抓住这一次机会,程序的回光返照就是finalize()方法,因为finalize()只会执行一次。

这里给出例子,演示这种情况,看下面的例子:

  1. public class CanObj {
  2. public static CanObj canObj;
  3. @Override
  4. public String toString() {
  5. return " i am canObj";
  6. }
  7. @Override
  8. protected void finalize() throws Throwable {
  9. super.finalize();
  10. System.out.println("finalize");
  11. this.canObj=this;
  12. }
  13. public static void main(String[] args) throws Exception {
  14. canObj=new CanObj();
  15. canObj=null;
  16. System.gc();
  17. Thread.sleep(1000);
  18. if (canObj==null) {
  19. System.out.println("canObj null ");
  20. }else {
  21. System.out.println("canObj is not null");
  22. }
  23. System.out.println("第二次GC");
  24. canObj=null;
  25. System.gc();
  26. Thread.sleep(1000);
  27. if (canObj==null) {
  28. System.out.println("canObj null ");
  29. }else {
  30. System.out.println("canObj is not null");
  31. }
  32. }
  33. }

运行以上代码,输出如下:

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>

下面演示软引用在系统堆内存不足的时候被回收。

  1. public class SoftRef {
  2. public static class User{
  3. private int id;
  4. private String name;
  5. public User(int id, String name) {
  6. this.id = id;
  7. this.name = name;
  8. }
  9. @Override
  10. public String toString() {
  11. return "User [id=" + id + ", name=" + name + "]";
  12. }
  13. }
  14. public static void main(String[] args) {
  15. User user=new User(1, "shareniu");
  16. SoftReference<User> usSoftReference=new SoftReference<SoftRef.User>(user);
  17. user=null;
  18. System.out.println(usSoftReference.get());
  19. System.gc();
  20. System.out.println("after gc");
  21. System.out.println(usSoftReference.get());
  22. byte []b=new byte[7*925*1024];
  23. System.gc();
  24. System.out.println(usSoftReference.get());
  25. }
  26. }

配置参数-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>

下面的例子显示弱引用的特点:

  1. public class WakRef {
  2. public static class User{
  3. private int id;
  4. private String name;
  5. public User(int id, String name) {
  6. this.id = id;
  7. this.name = name;
  8. }
  9. @Override
  10. public String toString() {
  11. return "User [id=" + id + ", name=" + name + "]";
  12. }
  13. }
  14. public static void main(String[] args) {
  15. User user=new User(1, "shareniu");
  16. WeakReference<User> weakReference=new WeakReference<WakRef.User>(user);
  17. user=null;
  18. System.out.println(weakReference.get());
  19. System.gc();
  20. System.out.println("after gc");
  21. System.out.println(weakReference.get());
  22. }
  23. }

程序输出如下:

User [id=1, name=shareniu]

after gc

null

可以看出,在GC之后,弱引用立即被清除了。

弱引用的时候可以构造一个队列,当弱引用对象被回收的时候,就会加入引用队列,通过对了可以追踪对象的回收情况。(在下面的通用例子中会降到)

1.2.4. 虚引用--对象回收追踪

虚引用是所有引用类型中最弱的一个,一个持有虚引用对象。和没有引用基本一样,随时都有可能被回收,当试图使用虚引用的get()获取的时候,总会失败报错,不能获取到。虚引用必须和引用队列一起使用,它的作用就是跟踪垃圾回收的过程。

当垃圾回收器回收一个对象的时候,如果发现他是虚引用,会立马讲这个虚引用的对象加入引用队列,通知应用程序对象的回收情况。所以我们在这里看一下队列如何使用。(除了强引用不能使用队列,其他的三个都可以使用,虚引用是必须使用队列

下面给出一个实例,使用虚引用跟踪一个可以复活的对象的回收。

  1. public class TraceObj {
  2. @Override
  3. public String toString() {
  4. return "TraceObj ";
  5. }
  6. public static TraceObj obj;
  7. //定义一个队列,对象回收时候会进入这个队列
  8. static ReferenceQueue<TraceObj> queue=null;
  9. public static class CheckRefQuene extends Thread{
  10. @Override
  11. public void run() {
  12. while (true) {
  13. if (queue!=null) {
  14. PhantomReference<TraceObj> phantomReference=null;
  15. try {
  16. phantomReference=(PhantomReference<TraceObj>) queue.remove();
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }
  20. if (phantomReference!=null) {
  21. System.out.println(" delete "+phantomReference);
  22. }
  23. }
  24. }
  25. }
  26. }
  27. @Override
  28. protected void finalize() throws Throwable {
  29. super.finalize();
  30. System.out.println("复活一个对象");
  31. //复活一个对象 finalize只会执行一次
  32. obj=this;
  33. }
  34. public static void main(String[] args) throws Exception {
  35. Thread thread=new CheckRefQuene();
  36. thread.setDaemon(true);
  37. thread.start();
  38. queue=new ReferenceQueue<TraceObj>();
  39. obj=new TraceObj();
  40. PhantomReference<TraceObj> phantomReference=new PhantomReference<TraceObj>(obj, queue);
  41. obj=null;
  42. System.gc();
  43. Thread.sleep(1000);
  44. if (obj==null) {
  45. System.out.println("null ");
  46. }else {
  47. System.out.println("obj is not null ");
  48. }
  49. System.out.println("第二次gc");
  50. obj=null;
  51. System.gc();
  52. Thread.sleep(1000);
  53. if (obj==null) {
  54. System.out.println("null ");
  55. }else {
  56. System.out.println("obj is not null ");
  57. }
  58. }
  59. }

程序的输出如下:

复活一个对象

obj is not null

第二次gc

delete java.lang.ref.PhantomReference@1d86fd3  (删除的对象确实进入队列了)

null

虚引用对象可以跟踪对象的回收时间,所以,可以将一些资源释放操作放在虚引用中执行和记录。

1.2.5. 比较

软、弱、和虚 引用都可以放置到队列中,强引用不需要,虚引用必须要使用队列。

软引用可以放一些缓存的数据,当内存不足的时候被回收

软引用在设备内存比较少的时候特别有用,比如android系统。

一个android应用如果设计到通过网络获取图片,为了让系统更快的运行和更节省流量我们可以将已经下载下来的图片缓存起来,当第二次浏览到该图片时就可以从缓存中拿。

缓存的方式有:一是放在系统内存中这样效率最高,二是把文件写到外部存储器上。但是就目前而言android系统的内存是非常的有限的不可能像PC机那样配置那么高的内存,而且外部存储器的容量也是有限的。

如何我们用SoftReference的方式存储在内存中是一中很好的解决方法(当然不止这一种)。

虚引用对象可以跟踪对象的回收时间,所以,可以将一些资源释放操作放在虚引用中执行和记录。

GC真正的垃圾:强、软、弱、和虚 对象的更多相关文章

  1. java中强,软,弱,虚引用 以及WeakHahMap

    java中强,软,弱,虚引用  以及WeakHahMap   一:强软引用: 参考:http://zhangjunhd.blog.51cto.com/113473/53092/进行分析   packa ...

  2. java中的强,软,弱,虚引用

    引用的应用场景 我们都知道垃圾回收器会回收符合回收条件的对象的内存,但并不是所有的程序员都知道回收条件取决于指向该对象的引用类型.这正是Java中弱引用和软引用的主要区别. 如果一个对象只有弱引用指向 ...

  3. [翻译] 编写高性能 .NET 代码--第二章 GC -- 减少大对象堆的碎片,在某些情况下强制执行完整GC,按需压缩大对象堆,在GC前收到消息通知,使用弱引用缓存对象

    减少大对象堆的碎片 如果不能完全避免大对象堆的分配,则要尽量避免碎片化. 对于LOH不小心就会有无限增长,但LOH使用的空闲列表机制可以减轻增长的影响.利用这个空闲列表,我们可以在两块分配区域中间找到 ...

  4. JVM-gcRoots 和 强引用,软引用, 弱引用, 虚引用, 代码演示和应用场景

    什么是垃圾? 什么是gcRoots, 谈谈你对 强, 软, 弱 , 虚引用的理解, 他们的应用场景 jvm采用可达性分析法: 从gcRoots集合开始,自上向下遍历,凡是在引用链上的对象,都不是垃圾, ...

  5. 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用

    垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...

  6. Java:对象的强、软、弱、虚引用

    转自: http://zhangjunhd.blog.51cto.com/113473/53092 1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无 ...

  7. 【转载】 Java 7之基础 - 强引用、弱引用、软引用、虚引用

    原文地址:http://blog.csdn.net/mazhimazh/article/details/19752475 1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一 ...

  8. Java中四种引用:强、软、弱、虚引用

    这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...

  9. Java:对象的强、软、弱和虚引用

    1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK ...

随机推荐

  1. [NOIp 2013]货车运输

    Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重 ...

  2. 计蒜客NOIP模拟赛(3) D1T2 信息传递

    一个数据包在一个无向网络中传递.在时刻0,该数据包将依照特定的概率随机抵达网络中的某个节点.网络可以看做一张完全带权无向图,包含N个节点,若t时刻数据包在节点i,则在t+1时刻,数据包被传递到节点j的 ...

  3. SAM维护的在线LCS

    题目大意: 给定两个字符串,存在三种操作,分别是在a,b串末尾加一个字符串,和询问两串的LCS 题解: Get新套路:把两串建在同一SAM上,将重合的位置合并为同一节点,再加个标记数组,如果两者的LC ...

  4. bzoj2683简单题 cdq分治

    2683: 简单题 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 1803  Solved: 731[Submit][Status][Discuss] ...

  5. bzoj1127[POI2008]KUP 悬线法

    Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 485  Solved: 174[Submit][Status][D ...

  6. salt基本使用之二(2)

    1.Event和Reactor Event是saltstack里面的对每个事件的一个记录,相比job更加底层. 一,查看Event事件 可以在master下再开一个终端执行以下命令可以查看Event事 ...

  7. P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解

    1.内容概述 P2P即点对点通信,或称为对等联网,与传统的服务器客户端模式(如下图"P2P结构模型"所示)有着明显的区别,在即时通讯方案中应用广泛(比如IM应用中的实时音视频通信. ...

  8. sqlserver 按照特定值排序查询结果

    select * from t_ss_student order by case when xm like '林%' then 1 else 2 end asc; 姓林的会排在前面

  9. 网易笔试题:浏览器中输入一个url后回车到返回页面信息的过程

    You enter a URL into the browser输入一个url地址 The browser looks up the IP address for the domain name浏览器 ...

  10. React框架 dva 和 mobx 的使用感受

    最近在用react写web项目,领导为了让前端便于维护要求都用react作为开发基础,框架选型不限.在使用 react 的时候或多或少会接触到状态管理,从开始学 react 到现在也挺久了,做一些前端 ...