• 引用和可触及性的强度


    java中提供了四个级别的引用:强引用、软引用、弱引用和虚引用
    除强引用外,其它三种均可以在java.lang.ref包中找到它们的身影。
    强引用就是程序中一般使用的引用类型,强引用对象是可触及的,不会被回收。
    相对的,软引用、弱引用和虚引用的对象是软可触及、弱可触及和虚可触及的,在一定条件下,都可以被回收。

    强引用
    /**
    * Created by wb-xxd249566 on 2017/4/5.
    */
    public class StrongReference {
    public static void main(String[] args){
    StringBuffer str = new StringBuffer("Hello world");
    }
    }
    此段代码运行时,str将被分配在java栈上,而对象StringBuffer实例则被分配在堆上。
    局部变量str指向StringBuffer实例所在堆空间,通过str可操作该实例,那么str就是StringBuffer实例的强引用。
    此时如果再加一条赋值语句:
    /**
    * Created by wb-xxd249566 on 2017/4/5.
    */
    public class StrongReference {
    public static void main(String[] args){
    StringBuffer str = new StringBuffer("Hello world");
    StringBuffer str1 = str;
    }
    }
    这样str所指向的引用也会被str1所指向,同时在局部变量表上会分配空间存放局部变量str1,此时,该StringBuffer实例就有俩个引用了。

    对引用的"=="操作用于表示俩操作数所指向的堆空间的地址是否相同,不表示俩操作数所指向的对象是否相等。

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

    软引用
    import java.lang.ref.SoftReference;

    /**
    * Created by wb-xxd249566 on 2017/4/5.
    * -Xmx10m
    */
    public class SoftRef {
    public static class User{
    public User(int id,String name){
    this.id = id;
    this.name = name;
    }
    public int id;
    public String name;

    @Override
    public String toString() {
    return "[id="+String.valueOf(id)+",name="+name+"]";
    }
    }

    public static void main(String[] args){
    User u = new User(1,"xxd");
    SoftReference<User> userSoftRef = new SoftReference<>(u);
    u = null;

    System.out.println(userSoftRef.get());
    System.gc();
    System.out.println("After GC");
    System.out.println(userSoftRef.get());

    byte[] b = new byte[1024*925*7];
    System.gc();
    System.out.println(userSoftRef.get());
    }

    }
    讲道理,由强引用u创建的软引用userSoftRef,在分配了byte[]数组后,内存紧张,应该被GC清除掉,但是在我的计算机上并没有把它清除
    由此可见,在我的计算机上,相同的配置,在分配了1024*925*7这么大空间后,并没有使系统感觉资源紧张,因此没有回收该软引用,修改参数,最终在分配了1024*937*7的空间后
    byte[] b = new byte[1024*937*7];
    执行结果:
    所以从该示例中可以看出,GC 未必会回收软引用的对象,但是当内存资源紧张时,软引用对象会被回收,所以软引用对象不会引起内存溢出
    每一个软引用都可以附带一个引用队列,当对象的可达性状态发生变化时(由可达变为不可达),软引用对象就会进入引用队列,可以跟踪对象的回收状况。
    import java.lang.ref.ReferenceQueue;
    import java.lang.ref.SoftReference;

    /**
    * Created by wb-xxd249566 on 2017/4/5.
    */
    public class SoftRefQ {
    public static class User{
    public User(int id,String name){
    this.id = id;
    this.name = name;
    }
    public int id;
    public String name;

    @Override
    public String toString() {
    return "[id="+String.valueOf(id)+",name="+name+"]";
    }
    }

    static ReferenceQueue<User> softQueue = null;
    public static class CheckRefQueue extends Thread{
    @Override
    public void run() {
    while (true){
    if (softQueue != null){
    UserSoftReference obj = null;
    try {
    obj = (UserSoftReference) softQueue.remove();
    }catch (InterruptedException e){
    e.printStackTrace();
    }
    if (obj!=null)
    System.out.println("user id "+obj.uid+" is deleted");
    }
    }
    }
    }

    public static class UserSoftReference extends SoftReference<User>{
    int uid;
    public UserSoftReference(User referent, ReferenceQueue<? super User> q){
    super(referent,q);
    uid = referent.id;
    }
    }

    public static void main(String[] args) throws InterruptedException{
    Thread t = new CheckRefQueue();
    t.setDaemon(true);
    t.start();
    User u = new User(1,"xxd");
    softQueue = new ReferenceQueue<>();
    UserSoftReference userSoftRef = new UserSoftReference(u,softQueue);
    u = null;
    System.out.println(userSoftRef.get());
    System.gc();
    System.out.println("After GC");
    System.out.println(userSoftRef.get());

    System.out.println("try to create byte array and GC");
    byte[] b = new byte[1024*937*7];
    System.gc();
    System.out.println(userSoftRef.get());

    Thread.sleep(1000);
    }
    }
    执行结果(-Xmx10m):
    弱引用
    弱引用是一种比软引用较弱的引用类型。在系统GC时,只要发现弱引用,不管系统堆空间使用情况如何,都会将对象进行回收。
    一旦一个弱引用对象被垃圾回收器回收,便会加入到一个注册的引用队列中(与软引用类似)
    import java.lang.ref.WeakReference;

    /**
    * Created by wb-xxd249566 on 2017/4/5.
    */
    public class WeakRef {
    public static class User{
    public User(int id,String name){
    this.id = id;
    this.name = name;
    }
    public int id;
    public String name;

    @Override
    public String toString() {
    return "[id="+String.valueOf(id)+",name="+name+"]";
    }
    }

    public static void main(String[] args){
    User u = new User(1,"xxd");
    WeakReference<User> userWeakReference = new WeakReference<>(u);
    u = null;
    System.out.println(userWeakReference.get());
    System.gc();
    System.out.println("After GC");
    System.out.println(userWeakReference.get());
    }
    }
    执行结果:
    软引用、弱引用都非常适合来保存那些可有可无的缓存数据。如果这么做,当系统内存不足时,这些缓存数据会被回收,不会导致内存溢出。而当内存资源充足时,这些缓存数据又可以存在相当长的时间,从而起到加速系统的作用。
    虚引用
    虚引用是所有引用当中类型最弱的一个。一个持有虚引用的对象,和没有引用几乎是一模一样的,随时都可能被垃圾回收器回收。
    当视图通过虚引用的get()方法取得强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。
    当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象后,将这个虚引用加入引用队列,以通知应用程序对象的回收情况。
    import java.lang.ref.PhantomReference;
    import java.lang.ref.ReferenceQueue;

    /**
    * Created by wb-xxd249566 on 2017/4/5.
    */
    public class TraceCanReliveObj {
    public static TraceCanReliveObj obj;
    static ReferenceQueue<TraceCanReliveObj> phantomQueue = null;
    public static class CheckRefQueue extends Thread{
    @Override
    public void run() {
    while (true){
    if (phantomQueue != null){
    PhantomReference<TraceCanReliveObj> objt = null;
    try {
    objt = (PhantomReference<TraceCanReliveObj>) phantomQueue.remove();
    }catch (InterruptedException e){
    e.printStackTrace();
    }
    if(objt!=null){
    System.out.println("TraceCanReliveObj is delete by GC");
    }
    }
    }
    }
    }

    @Override
    protected void finalize() throws Throwable {
    super.finalize();
    System.out.println("CanReliveObj finalize called");
    obj =this;
    }

    @Override
    public String toString() {
    return "I am CanReliveObj";
    }

    public static void main(String[] args) throws InterruptedException{
    Thread t = new CheckRefQueue();
    t.setDaemon(true);
    t.start();

    phantomQueue = new ReferenceQueue<>();
    obj = new TraceCanReliveObj();
    PhantomReference<TraceCanReliveObj> phantomReference = new PhantomReference<>(obj,phantomQueue);

    obj = null;
    System.gc();
    Thread.sleep(1000);
    if (obj == null){
    System.out.println("obj is null");
    }else{
    System.out.println("obj is useful");
    }
    System.out.println("The second GC");
    obj = null;
    System.gc();
    Thread.sleep(1000);
    if (obj == null) {
    System.out.println("obj is null");
    }else{
    System.out.println("obj is useful");
    }
    }
    }
    由于虚引用可以跟踪对象的回收时间,因此,可以将一些资源释放操作放置在虚引用中执行和记录

  • 相关阅读:
    本月周六周日LIST集合
    c#动态调用WEBSERVICE接口
    c#调用
    web上传下载文件
    MVC 的知识
    MongoDB 无法创建抽象类的问题,
    并行活动
    C# 字符串计算表达式
    c# 将字符串转换为逻辑表达式(字符串转换布尔)
    C# 中间语言、CLR、CTS、CLS
  • 原文地址:https://www.cnblogs.com/xxdfly/p/6670319.html
Copyright © 2020-2023  润新知