java强引用,软引用,弱引用,虚引用

原文:https://blog.csdn.net/liaodehong/article/details/52223354

用了Java怎么长时间一直不知道原来Java还有四种引用类型,这个引用类型和我们平常说的可不一样。这里的引用类型不是指数据类型的一种,而是指Java中的引用所分的四种类型。他们代表了JVM回收内存的四种强度,分别如下。

强引用:
Java中的引用,有点像C++的指针。通过引用,可以对堆中的对象进行操作。在某函数中,当创建了一个对象,该对象被分配在堆中,通过这个对象的引用才能对这个对象进行操作。

  1. Object o = new Object();

假设以上代码是在函数体内运行的,那么局部变量o将被分配在栈上,而对象实例,被分配在堆上。局部变量o指向Object实例所在的堆空间,通过o可以操作该实例,那么o就是Object的引用。

如果再创建一个赋值语句

  1. Object oj = o;

那么o指向的Object内存空间也会被oj所指向,此时我们可以说oj==o,那么ob.equals也肯定相等,即两个对象的值也肯定一样,当修改了o对象的时候,oj对象也会发生变化,或者当修改了oj对象的时候o对象也肯定会变化。所以如果想复制另外一个对象的值的话千万不要用这种方式,在多线程的情况下可能会有更槽糕的情况发生,你可以使用JDK自带的克隆方法,也可以重写克隆方法。

  1. public class Test1 {
  2. public static void main(String[] args) {
  3. student S=new student("1","我是大s");
  4. student s=S;
  5. System.out.println(s==S); //true
  6. System.out.println(s.equals(S)); //true
  7. System.out.println("打印出大S"+S); //id=1
  8. System.out.println("打印出小s"+s); //id=1
  9. S.setId("2");
  10. System.out.println("修改后的大S"+S); //id=2
  11. System.out.println("未修改后的小s"+s); //id=2
  12. s.setId("3");
  13. System.out.println("未修改后的大S"+S); //id=3
  14. System.out.println("修改后的小s"+s); //id=3
  15.  
  16. }
  17. }
  18. class student{
  19. String name;
  20. String id;
  21. public String getName() {
  22. return name;
  23. }
  24. public void setName(String name) {
  25. this.name = name;
  26. }
  27. public String getId() {
  28. return id;
  29. }
  30. public void setId(String id) {
  31. this.id = id;
  32. }
  33. public student(String name, String id) {
  34. super();
  35. this.name = name;
  36. this.id = id;
  37. }
  38. @Override
  39. public String toString() {
  40. return "student [name=" + name + ", id=" + id + "]";
  41. }
  42.  
  43. }

上例中的大S和小S都是强引用,强引用具有如下特点:

1.强引用可以直接访问目标对象。

2.强引用所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出OOM异常,也不会回收强引用所指向的对象。

3.强引用可能导致内存泄漏,为了避免内存泄漏,在使用完成之后我们可以把字符串对象设置为null,如果是集合的话可以使用

  1. List list=new ArrayList<>();
  2. list.clear();

软引用:
软引用的强度是仅次于强引用的,如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

我们可以使用java.lang.ref.SoftReference来创建软引用;

  1. String str=new String("abc"); // 强引用
  2. SoftReference<String> softRef=new SoftReference<String>(str); // 软引用

当内存不足时,等价于:

  1. If(JVM.内存不足()) {
  2. str = null; // 转换为空引用
  3. System.gc(); // 垃圾回收器进行回收
  4. }

弱引用:
弱引用的强度比软引用更次,也就是说只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

如果这个对象是偶尔的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么你应该用 Weak Reference 来标记此对象。

  1. String str=new String("abc");
  2. WeakReference<String> abcWeakRef = new WeakReference<String>(str);
  3. str=null;

如果你想把这个对象变成强引用的话可以使用

  1. String abc = abcWeakRef.get();

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

当你想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。

这个引用不会在对象的垃圾回收判断中产生任何附加的影响。

  1. public class ReferenceTest {
  2.  
  3. private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();
  4.  
  5. public static void checkQueue() {
  6. Reference<? extends VeryBig> ref = null;
  7. while ((ref = rq.poll()) != null) {
  8. if (ref != null) {
  9. System.out.println("In queue: " + ((VeryBigWeakReference) (ref)).id);
  10. }
  11. }
  12. }
  13.  
  14. public static void main(String args[]) {
  15. int size = 3;
  16. LinkedList<WeakReference<VeryBig>> weakList = new LinkedList<WeakReference<VeryBig>>();
  17. for (int i = 0; i < size; i++) {
  18. weakList.add(new VeryBigWeakReference(new VeryBig("Weak " + i), rq));
  19. System.out.println("Just created weak: " + weakList.getLast());
  20.  
  21. }
  22.  
  23. System.gc();
  24. try { // 下面休息几分钟,让上面的垃圾回收线程运行完成
  25. Thread.currentThread().sleep(6000);
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. }
  29. checkQueue();
  30. }
  31. }
  32.  
  33. class VeryBig {
  34. public String id;
  35. // 占用空间,让线程进行回收
  36. byte[] b = new byte[2 * 1024];
  37.  
  38. public VeryBig(String id) {
  39. this.id = id;
  40. }
  41.  
  42. protected void finalize() {
  43. System.out.println("Finalizing VeryBig " + id);
  44. }
  45. }
  46.  
  47. class VeryBigWeakReference extends WeakReference<VeryBig> {
  48. public String id;
  49.  
  50. public VeryBigWeakReference(VeryBig big, ReferenceQueue<VeryBig> rq) {
  51. super(big, rq);
  52. this.id = big.id;
  53. }
  54.  
  55. protected void finalize() {
  56. System.out.println("Finalizing VeryBigWeakReference " + id);
  57. }
  58. }

虚引用
虚引用顾名思义就是形同虚设,虚引用也称为幻影引用:一个对象是都有虚引用的存在都不会对生存时间都构成影响,也无法通过虚引用来获取对一个对象的真实引用。唯一的用处:能在对象被GC时收到系统通知,JAVA中用PhantomReference来实现虚引用。

对比不同:

  1. import java.lang.ref.Reference;
  2. import java.lang.ref.SoftReference;
  3. import java.lang.ref.WeakReference;
  4. import java.lang.ref.PhantomReference;
  5. import java.lang.ref.ReferenceQueue;
  6. import java.util.Set;
  7. import java.util.HashSet;
  8.  
  9. class Grocery {
  10. private static final int SIZE = 10000;
  11. // 属性d使得每个Grocery对象占用较多内存,有80K左右
  12. private double[] d = new double[SIZE];
  13. private String id;
  14. public Grocery(String id) {
  15. this.id = id;
  16. }
  17. public String toString() {
  18. return id;
  19. }
  20. /* public void finalize() { // 注意: finalize 在 Java 11 中已经被废弃
  21. System.out.println("即将回收 " + id);
  22. } */
  23. }
  24.  
  25. public class HelloWorld {
  26.  
  27. // 关联的引用队列 如果引用的对象被JVM回收 则这个引用就会被加入到与之关联的引用队列中
  28. private static ReferenceQueue<Grocery> rq = new ReferenceQueue<Grocery>();
  29.  
  30. public static void checkQueue() {
  31.  
  32. boolean flag = true;
  33. System.out.println(">>>>>>>>>>>>>>>>>>>>");
  34. while (flag) {
  35. Reference<? extends Grocery> inq = rq.poll(); // 从队列中取出一个引用
  36. if (inq != null) {
  37. flag = true;
  38. System.out.println("In queue: type ===> " + inq + " value ===> " + inq.get());
  39. } else {
  40. flag = false;
  41. System.out.println("In queue: " + "is null");
  42. }
  43. }
  44. System.out.println("<<<<<<<<<<<<<<<<<<<");
  45. }
  46.  
  47. public static void main(String[] args) {
  48. // 引用创建的固定数量
  49. final int size = 10;
  50.  
  51. // 创建10个Grocery对象以及10个软引用
  52. Set<SoftReference<Grocery>> sa = new HashSet<SoftReference<Grocery>>();
  53. for (int i = 0; i < size; i++) {
  54. SoftReference<Grocery> ref = new SoftReference<Grocery>(
  55. new Grocery("SoftReference " + i), rq);
  56. System.out.println("刚刚 创建了 软引用: " + ref.get());
  57. sa.add(ref);
  58. }
  59. System.gc();
  60. checkQueue();
  61.  
  62. // 创建10个Grocery对象以及10个弱引用
  63. Set<WeakReference<Grocery>> wa = new HashSet<WeakReference<Grocery>>();
  64. for (int i = 0; i < size; i++) {
  65. WeakReference<Grocery> ref = new WeakReference<Grocery>(
  66. new Grocery("WeakReference " + i), rq);
  67. System.out.println("刚刚 创建了 弱引用: " + ref.get());
  68. wa.add(ref);
  69. }
  70. System.gc();
  71. checkQueue();
  72.  
  73. // 创建10个Grocery对象以及10个虚引用
  74. Set<PhantomReference<Grocery>> pa = new HashSet<PhantomReference<Grocery>>();
  75. for (int i = 0; i < size; i++) {
  76. PhantomReference<Grocery> ref = new PhantomReference<Grocery>(
  77. new Grocery("PhantomReference " + i), rq);
  78. System.out.println("刚刚 创建了 虚引用 : " + ref.get());
  79. pa.add(ref);
  80. }
  81. System.gc();
  82. checkQueue();
  83. }
  84. }

控制台输出

  1. >javac -encoding utf-8 -d .\src .\src\HelloWorld.java
  2. >java -Dfile.encoding=utf-8 -cp .\src HelloWorld
  3. 刚刚 创建了 软引用: SoftReference 0
  4. 刚刚 创建了 软引用: SoftReference 1
  5. 刚刚 创建了 软引用: SoftReference 2
  6. 刚刚 创建了 软引用: SoftReference 3
  7. 刚刚 创建了 软引用: SoftReference 4
  8. 刚刚 创建了 软引用: SoftReference 5
  9. 刚刚 创建了 软引用: SoftReference 6
  10. 刚刚 创建了 软引用: SoftReference 7
  11. 刚刚 创建了 软引用: SoftReference 8
  12. 刚刚 创建了 软引用: SoftReference 9
  13. >>>>>>>>>>>>>>>>>>>>
  14. In queue: is null
  15. <<<<<<<<<<<<<<<<<<<
  16. 刚刚 创建了 弱引用: WeakReference 0
  17. 刚刚 创建了 弱引用: WeakReference 1
  18. 刚刚 创建了 弱引用: WeakReference 2
  19. 刚刚 创建了 弱引用: WeakReference 3
  20. 刚刚 创建了 弱引用: WeakReference 4
  21. 刚刚 创建了 弱引用: WeakReference 5
  22. 刚刚 创建了 弱引用: WeakReference 6
  23. 刚刚 创建了 弱引用: WeakReference 7
  24. 刚刚 创建了 弱引用: WeakReference 8
  25. 刚刚 创建了 弱引用: WeakReference 9
  26. >>>>>>>>>>>>>>>>>>>>
  27. In queue: type ===> java.lang.ref.WeakReference@de0a01f value ===> null
  28. In queue: type ===> java.lang.ref.WeakReference@ba4d54 value ===> null
  29. In queue: type ===> java.lang.ref.WeakReference@4c75cab9 value ===> null
  30. In queue: type ===> java.lang.ref.WeakReference@6aceb1a5 value ===> null
  31. In queue: type ===> java.lang.ref.WeakReference@769c9116 value ===> null
  32. In queue: type ===> java.lang.ref.WeakReference@1ef7fe8e value ===> null
  33. In queue: type ===> java.lang.ref.WeakReference@12bc6874 value ===> null
  34. In queue: type ===> java.lang.ref.WeakReference@2d6d8735 value ===> null
  35. In queue: type ===> java.lang.ref.WeakReference@67117f44 value ===> null
  36. In queue: type ===> java.lang.ref.WeakReference@6f79caec value ===> null
  37. In queue: is null
  38. <<<<<<<<<<<<<<<<<<<
  39. 刚刚 创建了 虚引用 : null
  40. 刚刚 创建了 虚引用 : null
  41. 刚刚 创建了 虚引用 : null
  42. 刚刚 创建了 虚引用 : null
  43. 刚刚 创建了 虚引用 : null
  44. 刚刚 创建了 虚引用 : null
  45. 刚刚 创建了 虚引用 : null
  46. 刚刚 创建了 虚引用 : null
  47. 刚刚 创建了 虚引用 : null
  48. 刚刚 创建了 虚引用 : null
  49. >>>>>>>>>>>>>>>>>>>>
  50. In queue: type ===> java.lang.ref.PhantomReference@2cfb4a64 value ===> null
  51. In queue: type ===> java.lang.ref.PhantomReference@5474c6c value ===> null
  52. In queue: type ===> java.lang.ref.PhantomReference@7a92922 value ===> null
  53. In queue: type ===> java.lang.ref.PhantomReference@483bf400 value ===> null
  54. In queue: type ===> java.lang.ref.PhantomReference@71f2a7d5 value ===> null
  55. In queue: type ===> java.lang.ref.PhantomReference@4b6995df value ===> null
  56. In queue: type ===> java.lang.ref.PhantomReference@21a06946 value ===> null
  57. In queue: type ===> java.lang.ref.PhantomReference@326de728 value ===> null
  58. In queue: type ===> java.lang.ref.PhantomReference@77f03bb1 value ===> null
  59. In queue: type ===> java.lang.ref.PhantomReference@25618e91 value ===> null
  60. In queue: is null
  61. <<<<<<<<<<<<<<<<<<<

在上面的这个例子中,依次创建了十个10个软引用、10个弱引用和10个虚引用,它们各自引用一个Grocery对象。并且在创建之后调用GC方法。从程序运行时的打印结果可以看出,虚引用形同虚设,它所引用的对象随时可能被垃圾回收,具有弱引用的对象拥有稍微长的生命周期,当垃圾回收器执行回收操作时,有可能被垃圾回收,具有软引用的对象拥有较长的生命周期,但在Java虚拟机认为内存不足的情况下,也会被垃圾回收。

总结
强引用:就像是老板(OOM)的亲儿子一样,在公司可以什么事都不干,但是千万不要老是占用公司的资源为他自己做事,记得用完公司的妹子之后,要让她们去工作(资源要懂得释放) 不然公司很可能会垮掉的。
软引用:有点像老板(OOM)的亲戚,在公司表现不好有可能会被开除,即使你投诉他(调用GC)上班看片,但是只要不被老板看到(被JVM检测到)就不会被开除(被虚拟机回收)。
弱引用:就是一个普通的员工,平常如果表现不佳会被开除(对象没有其他引用的情况下),遇到别人投诉(调用GC)上班看片,那开除是肯定了(被虚拟机回收)。
虚引用:这货估计就是个实习生跟临时工把,遇到事情的时候想到了你,没有事情的时候,秒秒钟拿出去顶锅,开除。

================= End

java强引用,软引用,弱引用,虚引用的更多相关文章

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

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

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

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

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

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

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

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

  5. Java对象的强、软、弱和虚引用详解

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

  6. java基础知识再学习--集合框架-对象的强、软、弱和虚引用

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://zhangjunhd.blog.51cto.com/113473/53092 本文 ...

  7. Java对象的强、软、弱和虚引用原理+结合ReferenceQueue对象构造Java对象的高速缓存器

    //转 http://blog.csdn.net/lyfi01/article/details/6415726 1.Java对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变 ...

  8. Java:对象的强、软、弱和虚引用[转]

    原文链接:http://zhangjunhd.blog.51cto.com/113473/53092/ 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

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

    Java对象的强.软.弱和虚引用+ReferenceQueue 一.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内存空间不足 ...

  10. Java:对象的强、软、弱和虚引用的区别

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

随机推荐

  1. 重装系统之win10不能进入bios界面

    原因 自Win10发布以来,新出厂的预装Win10的电脑都默认在UEFI模式下启动操作系统.UEFI启动是一种新的主板引导项,正被看做是有近20多年历史的BIOS 的继任者.顾名思义,快速启动是可以提 ...

  2. Vue 开发环境搭建 (Mac)

    一.初识 由于个人工作原因以及技术需要一个提升,略晚的开始初探Vue ~.~ 二.那么Vue是什么呢? 他就是一个前端的框架,特点是数据双向绑定.组件化. 三.推荐开发环境 四.环境安装 打开终端运行 ...

  3. bitcoin源码解析 - 交易 Transcation (一)

    比特币中的交易可谓是比特币的最核心部分.比特币由交易产生,而区块就是用来存储交易的.所以,交易是比特币存在的载体,同时也是比特币中最复杂的部分.交易的运作层层相扣,各个部分缺一不可,十分严密,由此体现 ...

  4. Express4.x API (三):Response (译)

    Express4.x API 译文 系列文章 Express4.x API (一):application (译) -- 完成 Express4.x API (二):request (译) -- 完成 ...

  5. 生活沉思录 via 哲理小故事(一)

    1.小托蒂的悲剧 意大利小男孩托蒂,有一只十分奇怪的眼睛,因为从生理上看,这是一只完全正常的眼睛,但却是失明的. 原来,托蒂刚出生时,这只眼睛轻度感染,曾用绷带缠了两个星期.这对常人来说几乎没有人任何 ...

  6. Oracle_安装问题

    [INS-07003] 访问 BeanStore 时出现意外错误   oracle安装时出现以下问题: 原因:未配置环境变量CLASSPASH 解决方法:新增系统变量,在我的电脑上右击-属性-高级系统 ...

  7. 老牌阅读器nook2刷机整理

    kindle肯定是现在大多数人了解电纸书这个产品的开端,也给我留下了一段美好的回忆,不折腾,不死机,官方书城让人省心不少,不过作为半个折腾爱好者,kindle显然不符合我的理念,遂慢慢入了安卓电纸书的 ...

  8. Vue 回顾之指令(关于input自动聚焦的问题)

    用了Vue也一年多了,虽然对大部分内容都比较熟悉,但有些用法可能会起到意想不到的作用. 今天在做一个关于抽奖的需求,要求是每次点击编辑按钮显示编辑框,要求自动聚焦. 一开始想到了autofocus属性 ...

  9. C_数据结构_递归不同函数间调用

    # include <stdio.h> void f(); void g(); void k(); void f() { printf("FFFF\n"); g(); ...

  10. C++STL——优先队列

    一.相关定义 优先队列容器与队列一样,只能从队尾插入元素,从队首删除元素.但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队.这 ...