当前位置: 首页 > article >正文

强引用和弱引用区别

强引用
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。如下:

  Object strongReference = new Object();


当内存空间不足时,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
如果强引用对象不使用时,需要弱化从而使GC能够回收,如下:

strongReference = null;


显式地设置strongReference对象为null,或让其超出对象的生命周期范围,则gc认为该对象不存在引用,这时就可以回收这个对象。具体什么时候收集这要取决于GC算法。

  public void test() {
        Object strongReference = new Object();
        // 省略其他操作
    }



在一个方法的内部有一个强引用,这个引用保存在Java栈中,而真正的引用内容(Object)保存在Java堆中。
当这个方法运行完成后,就会退出方法栈,则引用对象的引用数为0,这个对象会被回收。
但是如果这个strongReference是全局变量时,就需要在不用这个对象时赋值为null,因为强引用不会被垃圾回收。

比如ArraryList类的clear方法中就是通过将引用赋值为null来实现清理工作的:

public void clear() {
      modCount++;
 
      // Let gc do its work
      for (int i = 0; i < size; i++)
          elementData[i] = null;
 
      size = 0;
}


在ArrayList类中定义了一个私有的变量elementData数组,在调用方法清空数组时可以看到为每个数组内容赋值为null。不同于elementData=null,强引用仍然存在,避免在后续调用 add()等方法添加元素时进行重新的内存分配。使用如clear()方法中释放内存的方法对数组中存放的引用类型特别适用,这样就可以及时释放内存。

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

 String str = new String("abc");
    WeakReference<String> weakReference = new WeakReference<>(str);
    str = null;



JVM首先将软引用中的对象引用置为null,然后通知垃圾回收器进行回收:

   str = null;
    System.gc();



注意:如果一个对象是偶尔(很少)的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么你应该用Weak Reference来记住此对象。
下面的代码会让一个弱引用再次变为一个强引用:

 String str = new String("abc");
    WeakReference<String> weakReference = new WeakReference<>(str);
    // 弱引用转强引用
    String strongReference = weakReference.get();



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

public class GCTarget {
    // 对象的ID
    public String id;

    // 占用内存空间
    byte[] buffer = new byte[1024];

    public GCTarget(String id) {
        this.id = id;
    }

    protected void finalize() throws Throwable {
        // 执行垃圾回收时打印显示对象ID
        System.out.println("Finalizing GCTarget, id is : " + id);
    }
}
public class GCTarget {
    // 对象的ID
    public String id;

    // 占用内存空间
    byte[] buffer = new byte[1024];

    public GCTarget(String id) {
        this.id = id;
    }

    protected void finalize() throws Throwable {
        // 执行垃圾回收时打印显示对象ID
        System.out.println("Finalizing GCTarget, id is : " + id);
    }
}
public class WeakReferenceTest {
    // 弱引用队列
    private final static ReferenceQueue<GCTarget> REFERENCE_QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) {
        LinkedList<GCTargetWeakReference> gcTargetList = new LinkedList<>();

        // 创建弱引用的对象,依次加入链表中
        for (int i = 0; i < 5; i++) {
            GCTarget gcTarget = new GCTarget(String.valueOf(i));
            GCTargetWeakReference weakReference = new GCTargetWeakReference(gcTarget,
                REFERENCE_QUEUE);
            gcTargetList.add(weakReference);

            System.out.println("Just created GCTargetWeakReference obj: " +
                gcTargetList.getLast());
        }

        // 通知GC进行垃圾回收
        System.gc();

        try {
            // 休息几分钟,等待上面的垃圾回收线程运行完成
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 检查关联的引用队列是否为空
        Reference<? extends GCTarget> reference;
        while((reference = REFERENCE_QUEUE.poll()) != null) {
            if(reference instanceof GCTargetWeakReference) {
                System.out.println("In queue, id is: " +
                    ((GCTargetWeakReference) (reference)).id);
            }
        }
    }
}


可见WeakReference对象的生命周期基本由垃圾回收器决定,一旦垃圾回收线程发现了弱引用对象,在下一次GC过程中就会对其进行回收。


http://www.kler.cn/a/6161.html

相关文章:

  • 深度学习中的正则化方法
  • 30分钟学会css
  • Vue3+Element Plus的表格分页实战
  • 实时高保真人脸编辑方法PersonaMagic,可根据肖像无缝生成新角色、风格或场景图像。
  • C#—SynchronizationContext类详解 (同步上下文)
  • 数据分享:空气质量数据--哈尔滨
  • php面向对象讲解
  • 2023年全国最新保安员精选真题及答案42
  • 计算机网络中端到端与点到点的区别
  • 【创作赢红包】求最大公因数与最小公倍数
  • 【新2023Q2模拟题JAVA】华为OD机试 - 总最快检测效率 or 核酸检测效率
  • 【云原生进阶之容器】第五章容器运行时5.5--容器运行时之Kata Containers
  • 2023年南京晓庄学院五年一贯制专转本秘书学专业考试大纲
  • 让ChatGPT告诉你Java的发展前景
  • Java小课堂:自定义注解(案例:自定义DecimalFormat注解)
  • TiDB入门篇-数据物理备份和恢复
  • 损失函数:如何帮助模型学会“自省”?
  • 【Redis】数据结构 - HyperLogLog
  • 内存管理介绍
  • 3.docker-容器命令
  • Java标识符和关键字
  • 简单使用AndroidStudio 官方Profiler工具进行内存泄漏检查
  • [数据结构]冒泡排序、快速排序
  • 今天面了一个来京东要求月薪25K,明显感觉他背了很多面试题...
  • 浙江省高校计算机等级考试二级Python 程序设计题6——判断字符串长度|2023备考
  • python e指数函数,常用的e指数代码