首页 > 编程语言 >【java基础】java的强引用、弱引用、软引用、虚引用

【java基础】java的强引用、弱引用、软引用、虚引用

时间:2023-03-11 20:11:59浏览次数:53  
标签:java Object 基础 引用 key public delegate

前言

Java执行 GC(垃圾回收)判断对象是否存活有两种方式,分别是引用计数法和引用链法(可达性分析法)。

引用计数:Java堆中给每个对象都有一个引用计数器,每当某个对象在其它地方被引用时,该对象的计数器 +1;引用失效则 -1;

JDK 1.2版本开始,对象的引用被划分为 4种级别,使程序能更加灵活地控制对象的生命周期。这 4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

正文

(一) 强引用(StrongReference)

在一个线程内,无须引用直接可以使用的对象,强引用不会被JVM清理。我们平时申明变量使用的就是强引用,普通系统99%以上都是强引 用,比如,String s="Hello World"。

Java中的引用,有点像 C++的指针。通过引用,可以对堆中的对象进行操作。在Java 程序中,最常见的引用类型是强引用,它也是默认的引用类型。例如:StringBuffer str=new StringBuffer(“Hello World”);
当在Java语言中使用new 操作符创建一个新的对象,并将其赋值给一个变量的时候,这个变量就成为指向该对象的一个强引用。而判断一个对象是否存活的标准为是否存在指向这个对象的引用。

强引用具备以下特点:
(1)强引用可以直接访问目标对象。
(2)强引用所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出Out Of Memory异常也不会回收强引用所指向的对象。
(3)强引用可能导致内存泄漏。

通常来说,应用程序内部的内存泄露有两种情况。一种是虚拟机中存在程序无法使用的内存区域,另一种情况是程序中存在大量存活时间过长的对象。

 

(二) 软引用(SoftReference)


java中使用SoftRefence来表示软引用

软引用是除了强引用外最强的引用类型,我们可以通过java.lang.ref.SoftReference使用软引用。一个持有软引用的对象,它不会被JVM很快回收,JVM会根据当前堆的使用情况来判断何时回收。当堆使用率临近阙值时,才会去回收软引用的对象。只要有足够的内 存,软引用便可能在内存中存活相当长一段时间。通过软引用,垃圾回收器就可以在内存不足时释放软引用可达的对象所占的内存空间。保证程序正常工作。

通过一个软引用申明,JVM抛出OOM之前,清理所有的软引用对象。垃圾回收器某个时刻决定回收软可达的对象的时候,会清理软引用,并可选的把引用存放到一个引用队列(ReferenceQueue)。

 

(三) 弱引用(WeakReference)


java中使用WeakReference来表示弱引用。如果某个对象与弱引用关联,那么当JVM在进行垃圾回收时,无论内存是否充足,都会回收此类对象。

通过一个弱引用申明。类似弱引用,只不过 Java 虚拟机会尽量让软引用的存活时间长一些,迫不得已才清理。

 

(四) 虚引用(PhantomReference)

java中使用PhantomReference来表示虚引用。

通过一个虚引用申明。仅用来处理资源的清理问题,比Object里面的finalize机制更灵活。get方法返回的永远是null,Java虚拟机不负责清理虚引用,但是它会把虚引用放到引用队列里面。

虚引用的主要目的是在一个对象所占的内存被实际回收之前得到通知,从而可以进行一些相关的清理工作。弱引用之前的两种引用类型有很大的不同:首先虚引用在创建时必须提供一个引用队列作为参数;其次虚引用对象的get方法总是返回null,因此无法通过虚引用来获取被引用的对象。

 //强引用
        String S = "强 引用 森";
        //软引用
        SoftReference<String> stringSoftReference = new SoftReference<>(new String("软 引用 仔"));
        System.out.println(stringSoftReference.get());
        System.gc();
        System.out.println(stringSoftReference.get());
        //弱引用
        WeakReference<String> str = new WeakReference<>("弱reference 森");
        System.out.println(str.get());
        System.gc();  //通知JVM进行内存回收
        System.out.println(str.get());
        //虚引用
        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        PhantomReference<String> strs = new PhantomReference<>("虚引用 ", queue);
        System.out.println(strs.get());

        System.out.println(S);
        System.out.println(queue.poll());


//打印内容
软 引用 仔
软 引用 仔
弱reference 森
弱reference 森
null
强 引用 森
null
View Code

 

总结

Java中 4种引用的级别和强度由高到低依次为:强引用 -> 软引用 -> 弱引用 -> 虚引用

当垃圾回收器回收时,某些对象会被回收,某些不会被回收。垃圾回收器会从根对象 Object来标记存活的对象,然后将某些不可达的对象和一些引用的对象进行回收。

 

 

 

 

案例:mybatis的二级缓存就就有软引用和弱引用的缓存清空算法

案例一:软引用缓存清空算法

/**
 *    Copyright 2009-2020 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.cache.decorators;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Deque;
import java.util.LinkedList;

import org.apache.ibatis.cache.Cache;

/**
 * Soft Reference cache decorator
 * Thanks to Dr. Heinz Kabutz for his guidance here.
 *
 * @author Clinton Begin
 */
public class SoftCache implements Cache {
  private final Deque<Object> hardLinksToAvoidGarbageCollection;
  private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;
  private final Cache delegate;
  private int numberOfHardLinks;

  public SoftCache(Cache delegate) {
    this.delegate = delegate;
    this.numberOfHardLinks = 256;
    this.hardLinksToAvoidGarbageCollection = new LinkedList<>();
    this.queueOfGarbageCollectedEntries = new ReferenceQueue<>();
  }

  @Override
  public String getId() {
    return delegate.getId();
  }

  @Override
  public int getSize() {
    removeGarbageCollectedItems();
    return delegate.getSize();
  }

  public void setSize(int size) {
    this.numberOfHardLinks = size;
  }

  @Override
  public void putObject(Object key, Object value) {
    removeGarbageCollectedItems();
    delegate.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries));
  }

  @Override
  public Object getObject(Object key) {
    Object result = null;
    @SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache
    SoftReference<Object> softReference = (SoftReference<Object>) delegate.getObject(key);
    if (softReference != null) {
      result = softReference.get();
      if (result == null) {
        delegate.removeObject(key);
      } else {
        // See #586 (and #335) modifications need more than a read lock
        synchronized (hardLinksToAvoidGarbageCollection) {
          hardLinksToAvoidGarbageCollection.addFirst(result);
          if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
            hardLinksToAvoidGarbageCollection.removeLast();
          }
        }
      }
    }
    return result;
  }

  @Override
  public Object removeObject(Object key) {
    removeGarbageCollectedItems();
    return delegate.removeObject(key);
  }

  @Override
  public void clear() {
    synchronized (hardLinksToAvoidGarbageCollection) {
      hardLinksToAvoidGarbageCollection.clear();
    }
    removeGarbageCollectedItems();
    delegate.clear();
  }

  private void removeGarbageCollectedItems() {
    SoftEntry sv;
   //清空被垃圾回收触达内存不足时,被回收的缓存对象(数据已被清空,这里清空的仅仅是SoftEntry)
    while ((sv = (SoftEntry) queueOfGarbageCollectedEntries.poll()) != null) {
      delegate.removeObject(sv.key);
    }
  }

  private static class SoftEntry extends SoftReference<Object> {
    private final Object key;

    SoftEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) {
      super(value, garbageCollectionQueue);
      this.key = key;
    }
  }

}
View Code

案例二:弱引用缓存清空算法

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.cache.decorators;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Deque;
import java.util.LinkedList;

import org.apache.ibatis.cache.Cache;

/**
 * Weak Reference cache decorator.
 * Thanks to Dr. Heinz Kabutz for his guidance here.
 *
 * @author Clinton Begin
 */
public class WeakCache implements Cache {
  private final Deque<Object> hardLinksToAvoidGarbageCollection;
  private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;
  private final Cache delegate;
  private int numberOfHardLinks;

  public WeakCache(Cache delegate) {
    this.delegate = delegate;
    this.numberOfHardLinks = 256;
    this.hardLinksToAvoidGarbageCollection = new LinkedList<>();
    this.queueOfGarbageCollectedEntries = new ReferenceQueue<>();
  }

  @Override
  public String getId() {
    return delegate.getId();
  }

  @Override
  public int getSize() {
    removeGarbageCollectedItems();
    return delegate.getSize();
  }

  public void setSize(int size) {
    this.numberOfHardLinks = size;
  }

  @Override
  public void putObject(Object key, Object value) {
    removeGarbageCollectedItems();
    delegate.putObject(key, new WeakEntry(key, value, queueOfGarbageCollectedEntries));
  }

  @Override
  public Object getObject(Object key) {
    Object result = null;
    @SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache
    WeakReference<Object> weakReference = (WeakReference<Object>) delegate.getObject(key);
    if (weakReference != null) {
      result = weakReference.get();
      if (result == null) {
        delegate.removeObject(key);
      } else {
        hardLinksToAvoidGarbageCollection.addFirst(result);
        if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
          hardLinksToAvoidGarbageCollection.removeLast();
        }
      }
    }
    return result;
  }

  @Override
  public Object removeObject(Object key) {
    removeGarbageCollectedItems();
    return delegate.removeObject(key);
  }

  @Override
  public void clear() {
    hardLinksToAvoidGarbageCollection.clear();
    removeGarbageCollectedItems();
    delegate.clear();
  }

  private void removeGarbageCollectedItems() {
    WeakEntry sv;
    //清空弱引用结构体,其引用的数据对应已经在垃圾回收时被清空,这里只是清空WeakEntry
    while ((sv = (WeakEntry) queueOfGarbageCollectedEntries.poll()) != null) {
      delegate.removeObject(sv.key);
    }
  }

  private static class WeakEntry extends WeakReference<Object> {
    private final Object key;

    private WeakEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) {
      super(value, garbageCollectionQueue);
      this.key = key;
    }
  }

}
View Code

 

标签:java,Object,基础,引用,key,public,delegate
From: https://www.cnblogs.com/shangxiaofei/p/17206832.html

相关文章

  • HTML5简介与基础骨架
    HTML5简介与基础骨架 HTML5介绍HTML5是用来描述网页的一种语言,被称为超文本标记语言.用HTML5编写的文件,后缀以.html结尾HTML是一种标记语言,标记语言是一套标记标......
  • c++11标准右值引用, 移动语义和完美转发
    0.序言学习自C++RvalueReferencesExplained(thbecker.net)1.引入1.1拷贝间接资源如果一个类的成员变量有指针,例如classMyClass{public:T*element;}......
  • 【WPF】在xaml 中引用外部 程序间中图片或样式资源(SVG)
     在xaml中引用外部程序间中图片或样式资源(SVG)一、创建资源程序集1创建一个叫“IconPacks”C#类库程序集   删除自动生成的Class1.cs文件添加一个Themes文......
  • java生态下的后端开发都有哪些技术栈?
    前言    我08年毕业,大学跟着老师培训学习的C#,那时(2003-2010)它很是较时髦,毕业后就从事了winform窗体应用程序开发。慢慢的web网站兴起,就转到aps.net开发,再到后来就上......
  • Nginx基础 - 08路径Rewrite
     一、Rewrite基本描述rewrite主要实现url地址重写,以及重定向。 使用场景URL访问跳转:支持开发设计,页面跳转,兼容性支持SEO优化:依赖于url路径,以便......
  • nacos实现Java和.NetCore的服务注册和调用
    用nacos作为服务注册中心,如何注册.NetCore服务,如何在Java中调用.NetCore服务呢?可以分为下面几个步骤: 0.运行nacos 1.开发.netcore服务,然后调用nacos提供的.netcore......
  • 2023-03-11 Java中的动态数组
    类似C++中的vector,动态数组需要满足以下功能增(insert)删(remove)改(set)查(get和contain)支持泛型自动扩容和缩容上面的实现实际相当于JDK标准库中的java.util......
  • Java中值传递相关问题
    Java中只存在值传递,不存在引用传递1.如果形参是基本数据类型,那么形参拷贝的是实参变量的值2.如果形参是引用数据类型,那么形参拷贝的是实参变量的地址。二者本质都是值......
  • java基础二-面向对象的三大特性
    面向对象的是三大特性封装一.概念将类的信息隐藏在类的内部,不允许外部程序直接访问,通过类提供的方法实现对隐藏信息的操作和访问封装的两大原则尽可能多的东西藏起......
  • maven基础
    maven基础maven简介maven是什么maven的本质是一个项目管理工具,将项目开发和管理过程抽象为一个对象模型(POM)POM(ProjectObjectModel):项目对象模型maven的作用项......