强引用 ( Strong Reference )

强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。 ps:强引用其实也就是我们平时A a = new A()这个意思。

强引用特性

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

强引用所指向的对象在任何时候都不会被系统回收。

强引用可能导致内存泄漏。

Final Reference

当前类是否是finalizer类,注意这里finalizer是由JVM来标志的( 后面简称f类 ),并不是指java.lang.ref.Finalizer类。但是f类是会被JVM注册到java.lang.ref.Finalizer类中的。

① 当前类或父类中含有一个参数为空,返回值为void的名为finalize的方法。

② 并且该finalize方法必须非空

GC 回收问题

对象因为Finalizer的引用而变成了一个临时的强引用,即使没有其他的强引用,还是无法立即被回收;

对象至少经历两次GC才能被回收,因为只有在FinalizerThread执行完了f对象的finalize方法的情况下才有可能被下次GC回收,而有可能期间已经经历过多次GC了,但是一直还没执行对象的finalize方法;

CPU资源比较稀缺的情况下FinalizerThread线程有可能因为优先级比较低而延迟执行对象的finalize方法;

因为对象的finalize方法迟迟没有执行,有可能会导致大部分f对象进入到old分代,此时容易引发old分代的GC,甚至Full GC,GC暂停时间明显变长,甚至导致OOM;

对象的finalize方法被调用后,这个对象其实还并没有被回收,虽然可能在不久的将来会被回收。

软引用 ( Soft Reference )

是用来描述一些还有用但并非必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。

对于软引用关联着的对象,如果内存充足,则垃圾回收器不会回收该对象,如果内存不够了,就会回收这些对象的内存。在 JDK 1.2 之后,提供了 SoftReference 类来实现软引用。软引用可用来实现内存敏感的高速缓存。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

注意:Java 垃圾回收器准备对SoftReference所指向的对象进行回收时,调用对象的 finalize() 方法之前,SoftReference对象自身会被加入到这个 ReferenceQueue 对象中,此时可以通过 ReferenceQueue 的 poll() 方法取到它们。

/**

* 软引用:对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收( 因为是在第一次回收后才会发现内存依旧不充足,才有了这第二次回收 )。如果这次回收还没有足够的内存,才会抛出内存溢出异常。

* 对于软引用关联着的对象,如果内存充足,则垃圾回收器不会回收该对象,如果内存不够了,就会回收这些对象的内存。

* 通过debug发现,软引用在pending状态时,referent就已经是null了。

*

* 启动参数:-Xmx5m

*

*/

public class SoftReferenceDemo {

private static ReferenceQueue queue = new ReferenceQueue<>();

public static void main(String[] args) throws InterruptedException {

Thread.sleep(3000);

MyObject object = new MyObject();

SoftReference softRef = new SoftReference(object, queue);

new Thread(new CheckRefQueue()).start();

object = null;

System.gc();

System.out.println("After GC : Soft Get = " + softRef.get());

System.out.println("分配大块内存");

/**

* ====================== 控制台打印 ======================

* After GC : Soft Get = I am MyObject.

* 分配大块内存

* MyObject's finalize called

* Object for softReference is null

* After new byte[] : Soft Get = null

* ====================== 控制台打印 ======================

*

* 总共触发了 3 次 full gc。第一次有System.gc();触发;第二次在在分配new byte[5*1024*740]时触发,然后发现内存不够,于是将softRef列入回收返回,接着进行了第三次full gc。

*/

// byte[] b = new byte[5*1024*740];

/**

* ====================== 控制台打印 ======================

* After GC : Soft Get = I am MyObject.

* 分配大块内存

* Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

* at com.bayern.multi_thread.part5.SoftReferenceDemo.main(SoftReferenceDemo.java:21)

* MyObject's finalize called

* Object for softReference is null

* ====================== 控制台打印 ======================

*

* 也是触发了 3 次 full gc。第一次有System.gc();触发;第二次在在分配new byte[5*1024*740]时触发,然后发现内存不够,于是将softRef列入回收返回,接着进行了第三次full gc。当第三次 full gc 后发现内存依旧不够用于分配new byte[5*1024*740],则就抛出了OutOfMemoryError异常。

*/

byte[] b = new byte[5*1024*790];

System.out.println("After new byte[] : Soft Get = " + softRef.get());

}

public static class CheckRefQueue implements Runnable {

Reference obj = null;

@Override

public void run() {

try {

obj = (Reference) queue.remove();

} catch (InterruptedException e) {

e.printStackTrace();

}

if (obj != null) {

System.out.println("Object for softReference is " + obj.get());

}

}

}

public static class MyObject {

@Override

protected void finalize() throws Throwable {

System.out.println("MyObject's finalize called");

super.finalize();

}

@Override

public String toString() {

return "I am MyObject.";

}

}

}

弱引用 ( Weak Reference )

用来描述非必须的对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。一旦一个弱引用对象被垃圾回收器回收,便会加入到一个注册引用队列中。

注意:Java 垃圾回收器准备对WeakReference所指向的对象进行回收时,调用对象的 finalize() 方法之前,WeakReference对象自身会被加入到这个 ReferenceQueue 对象中,此时可以通过 ReferenceQueue 的 poll() 方法取到它们。

/**

* 用来描述非必须的对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发送之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。一旦一个弱引用对象被垃圾回收器回收,便会加入到一个注册引用队列中。

*/

public class WeakReferenceDemo {

private static ReferenceQueue queue = new ReferenceQueue<>();

public static void main(String[] args) {

MyObject object = new MyObject();

Reference weakRef = new WeakReference<>(object, queue);

System.out.println("创建的弱引用为 : " + weakRef);

new Thread(new CheckRefQueue()).start();

object = null;

System.out.println("Before GC: Weak Get = " + weakRef.get());

System.gc();

System.out.println("After GC: Weak Get = " + weakRef.get());

/**

* ====================== 控制台打印 ======================

* 创建的弱引用为 : java.lang.ref.WeakReference@1d44bcfa

* Before GC: Weak Get = I am MyObject

* After GC: Weak Get = null

* MyObject's finalize called

* 删除的弱引用为 : java.lang.ref.WeakReference@1d44bcfa , 获取到的弱引用的对象为 : null

* ====================== 控制台打印 ======================

*/

}

public static class CheckRefQueue implements Runnable {

Reference obj = null;

@Override

public void run() {

try {

obj = (Reference)queue.remove();

} catch (InterruptedException e) {

e.printStackTrace();

}

if(obj != null) {

System.out.println("删除的弱引用为 : " + obj + " , 获取到的弱引用的对象为 : " + obj.get());

}

}

}

public static class MyObject {

@Override

protected void finalize() throws Throwable {

System.out.println("MyObject's finalize called");

super.finalize();

}

@Override

public String toString() {

return "I am MyObject";

}

}

}

虚引用 ( Phantom Reference )

PhantomReference 是所有“弱引用”中最弱的引用类型。不同于软引用和弱引用,虚引用无法通过 get() 方法来取得目标对象的强引用从而使用目标对象,观察源码可以发现 get() 被重写为永远返回 null。

那虚引用到底有什么作用?其实虚引用主要被用来 跟踪对象被垃圾回收的状态,通过查看引用队列中是否包含对象所对应的虚引用来判断它是否 即将被垃圾回收,从而采取行动。它并不被期待用来取得目标对象的引用,而目标对象被回收前,它的引用会被放入一个 ReferenceQueue 对象中,从而达到跟踪对象垃圾回收的作用。

当phantomReference被放入队列时,说明referent的finalize()方法已经调用,并且垃圾收集器准备回收它的内存了。

注意:PhantomReference 只有当 Java 垃圾回收器对其所指向的对象真正进行回收时,会将其加入到这个 ReferenceQueue 对象中,这样就可以追综对象的销毁情况。这里referent对象的finalize()方法已经调用过了。

所以具体用法和之前两个有所不同,它必须传入一个 ReferenceQueue 对象。当虚引用所引用对象准备被垃圾回收时,虚引用会被添加到这个队列中。

Demo1:

/**

* 虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个持有虚引用的对象,和没有引用几乎是一样的,随时都有可能被垃圾回收器回收。

* 虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。

* 当phantomReference被放入队列时,说明referent的finalize()方法已经调用,并且垃圾收集器准备回收它的内存了。

*/

public class PhantomReferenceDemo {

private static ReferenceQueue queue = new ReferenceQueue<>();

public static void main(String[] args) throws InterruptedException {

MyObject object = new MyObject();

Reference phanRef = new PhantomReference<>(object, queue);

System.out.println("创建的虚拟引用为 : " + phanRef);

new Thread(new CheckRefQueue()).start();

object = null;

int i = 1;

while (true) {

System.out.println("第" + i++ + "次GC");

System.gc();

TimeUnit.SECONDS.sleep(1);

}

/**

* ====================== 控制台打印 ======================

* 创建的虚拟引用为 : java.lang.ref.PhantomReference@1d44bcfa

* 第1次GC

* MyObject's finalize called

* 第2次GC

* 删除的虚引用为: java.lang.ref.PhantomReference@1d44bcfa , 获取虚引用的对象 : null

* ====================== 控制台打印 ======================

*

* 再经过一次GC之后,系统找到了垃圾对象,并调用finalize()方法回收内存,但没有立即加入PhantomReference Queue中。因为MyObject对象重写了finalize()方法,并且该方法是一个非空实现,所以这里MyObject也是一个Final Reference。所以第一次GC完成的是Final Reference的事情。

* 第二次GC时,该对象(即,MyObject)对象会真正被垃圾回收器进行回收,此时,将PhantomReference加入虚引用队列( PhantomReference Queue )。

* 而且每次gc之间需要停顿一些时间,已给JVM足够的处理时间;如果这里没有TimeUnit.SECONDS.sleep(1); 可能需要gc到第5、6次才会成功。

*/

}

public static class MyObject {

@Override

protected void finalize() throws Throwable {

System.out.println("MyObject's finalize called");

super.finalize();

}

@Override

public String toString() {

return "I am MyObject";

}

}

public static class CheckRefQueue implements Runnable {

Reference obj = null;

@Override

public void run() {

try {

obj = (Reference)queue.remove();

System.out.println("删除的虚引用为: " + obj + " , 获取虚引用的对象 : " + obj.get());

System.exit(0);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

Q:

java 引用 引用的对象,Java 引用类型简述相关推荐

  1. java测试类生成对象,java编写student类 用Java编写一段测试程序,生成student类的两个对象,并输出每个对象基本信息?...

    java中怎么创建对象数组?比如我创建了一个学生类Student,怎么用这个类创建一个对象数组,麻烦给个例子? 学生类:classA{privateStringnameprivateintagepub ...

  2. java char的包装对象,Java 从Character和char的区别来学习自动拆箱装箱

    本文结构 1.Character和char 的区别: 2.自动拆箱装箱java 1.Character和char 的区别: Character是类,char基本数据类型.数组 在java中有三个类负责 ...

  3. java中的session对象,Java对象中Response与session对象的方法是什么?

    广州达内Java培训小编了解到Java对象种类很多,有的小伙伴最不清楚的就是Response与session对象的方法,下面小编就搜集Response与session对象的方法供大家阅读.当一个客户首 ...

  4. 头歌(educoder)第 5 章 Java 面向对象之类和对象 Java面向对象 - 类与对象

    目录 第1关:什么是类,如何创建类 第2关:构造方法 第3关:选择题(一)​编辑 第4关:This关键字 第5关:类与对象练习 第6关:static关键字 第7关:选择题(二) 第1关:什么是类,如何 ...

  5. 头歌(educoder)第 5 章 Java 面向对象之类和对象 Java面向对象 - 封装、继承和多态

    目录 第1关:什么是封装,如何使用封装 第2关:什么是继承,怎样使用继承 第3关:super关键字的使用 第4关:方法的重写与重载 第5关:抽象类 第6关:final关键字的理解与使用 第7关:接口 ...

  6. java获取运行时对象,java 面向对象(四十一):反射(五)反射应用二:获取运行时类的完整结构...

    我们可以通过反射,获取对应的运行时类中所有的属性.方法.构造器.父类.接口.父类的泛型.包.注解.异常等.... 典型代码: @Test public void test1(){ Class claz ...

  7. java作用域外调用对象,Java Web应用中往往通过设置不同作用域的属性来达到通讯的目的。 如果某个对象只在同一请求中共享,通过调用哪个类 的setAttribute方法设置属性。( )...

    [多选题]客源市场定位的依据包括(). [单选题]除了诗歌创作,作者的散文成就同样引人注目,其代表性的散文集是( )? [单选题]缩窄性心包炎指各种原因引起心包脏壁层炎症.纤维素性渗出物沉积,并逐渐机 ...

  8. java声明一个父类A,java 子类强转父类 父类强转子类

    1.基本数据类型 基本数据类型: 子类可以强转成父类,因为小范围可以强转大范围,不会有数据丢失. 父类也可以强转成子类,但是因为大范围强转成小范围,所以会有数据丢失. 2.Java 继承 继承就是子类 ...

  9. java强引用、软引用、弱引用、虚引用-Java的引用类型总共有四种,你都知道吗

    目录 谈引用 强引用(Strong Reference)--不回收 强引用例子 软引用(Soft Reference)--内存不足即回收 弱引用(Weak Reference)--发现即回收 面试题: ...

最新文章

  1. RDChiral | 用于处理立体化学的RDKit封装器
  2. R语言系统自带及附属包开元可用数据集汇总
  3. R可视化绘制卡方分布图(Chi-Square Distribution)
  4. 处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表
  5. CF1019D-Large Triangle【计算几何,二分】
  6. tidb数据库_异构数据库复制到TiDB
  7. LeetCode--80. 删除排序数组中的重复项Ⅱ(双指针,暴力)
  8. Android 系统(43)---HTTPS
  9. PDA开发从入门到精通
  10. POJ 3660 Cow Contest(Floyd求传递闭包(可达矩阵))
  11. android 号码区号判断,android 将手机号中间隐藏为星号(*)和手机号码判断
  12. 通过xml方式根据word模板导出word
  13. 水果 hdu 1263 模拟
  14. # 技术栈知识点巩固——Js
  15. 【华为诺亚方舟实验室】2021届毕业生招聘
  16. 『原创』统计建模与R软件-第四章 参数估计
  17. android蓝牙底层通道,底层之旅——Android蓝牙系统分析
  18. 机器学习助推分子动力学模拟
  19. mysql case when then end 和 if判断 常见使用方法
  20. 抗住千万流量的大型分布式系统架构设计

热门文章

  1. Java项目:ssm+mysql+jsp实现的校园二手市场交易平台源码
  2. python中while循环并列_Python中while循环的一个问题
  3. 破解excel格式保护
  4. GME轧空事件的战后处置和思考
  5. Windows Touchpad 报告描述符实例
  6. 一种锂电池充放电及外部供电自动切换的电路
  7. android usb ftdi,android-Nexus7 USB主机FTDI设备未检测到
  8. 如何下载网页上的图片
  9. springboot如何解析邮箱
  10. Wise Duplicate Finder(重复文件查找工具)v1.2.9.40中文免费版