精华内容
下载资源
问答
  • 其中,引用数据类型在存储堆中对需要引用的对象进行引用,引用是Java面向对象的一个特点,在Java入门中,我们会接触到四种Java的引用类型,接下来就说说这四种Java引用类型有哪些吧:1、Java中有哪几种引用?...

    Java类型一般有两种,即基本数据类型与引用数据类型。其中,引用数据类型在存储堆中对需要引用的对象进行引用,引用是Java面向对象的一个特点,在Java入门中,我们会接触到四种Java的引用类型,接下来就说说这四种Java引用类型有哪些吧:

    1、Java中有哪几种引用?它们的含义和区别是什么?

    从JDK1.2开始,Java中的引用类型分为四种,分别是:

    ①强引用(StrongReference)

    ②软引用(SoftRefernce)

    ③弱引用(WeakReference)

    ④虚引用(PhantomReference)

    强引用-StrongReference

    这种引用是平时开发中最常用的,例如Stringstrong=newString("StrongReference"),当一个实例对象具有强引用时,垃圾回收器不会回收该对象,当内存不足时,宁愿抛出OutOfMemeryError异常也不会通过回收强引用的对象,因为JVM认为强引用的对象是用户正在使用的对象,它无法分辨出到底该回收哪个,强行回收有可能导致系统严重错误。

    软引用-SoftReference

    如果一个对象只有软引用,那么只有当内存不足时,JVM才会去回收该对象,其他情况不会回收。软引用可以结合ReferenceQueue来使用,当由于系统内存不足,导致软引用的对象被回收了,JVM会把这个软引用加入到与之相关联的ReferenceQueue中。

    ReferenceQueuereferenceQueue=newReferenceQueue();

    SoftReferencesoftReference=newSoftReference<>(newBook(),referenceQueue);

    Bookbook=softReference.get();

    Referencereference=referenceQueue.poll();

    当系统内存不足时,触发gc,这个Book就会被回收,reference将不为null。

    弱引用-WeakReference

    只有弱引用的对象,当JVM触发gc时,就会回收该对象。与软引用不同的是,不管是否内存不足,弱引用都会被回收。弱引用可以结合ReferenceQueue来使用,当由于系统触发gc,导致软引用的对象被回收了,JVM会把这个弱引用加入到与之相关联的ReferenceQueue中,不过由于垃圾收集器线程的优先级很低,所以弱引用不一定会被很快回收。下面通过一个主动触发gc的例子来验证此结论。

    ReferenceQueuereferenceQueue=newReferenceQueue();

    WeakReferenceweakReference=newWeakReference(newBook(),referenceQueue);

    Bookbook=softReference.get();

    System.gc();

    //Runtime.getRuntime().gc();

    Referencereference=referenceQueue.poll();

    当然这不是每次都能复现,因为我们调用System.gc()只是告诉JVM该回收垃圾了,但是它什么时候做还是不一定的,但就我测试来看,只要多写几次System.gc(),复现的概率还是很高的。

    虚引用-PhantomReference

    如果一个对象只有虚引用在引用它,垃圾回收器是可以在任意时候对其进行回收的,虚引用主要用来跟踪对象被垃圾回收器回收的活动,当被回收时,JVM会把这个弱引用加入到与之相关联的ReferenceQueue中。与软引用和弱引用不同的是,虚引用必须有一个与之关联的ReferenceQueue,通过phantomReference.get()得到的值为null,试想一下,如果没有ReferenceQueue与之关联还有什么存在的价值呢?

    PhantomReferencephantomReference=newPhantomReference<>(newBook(),referenceQueue);

    Bookbook=phantomReference.get();//此值为null

    Referencereference=referenceQueue.poll();

    想了解更多Java知识,关注动力节点IT培训官网的Java资讯吧。

    展开全文
  • 关于深入理解java的引用类型:在java中,引用类型可以分为两大类:值类型,引用类型。其中值类型就是基本数据类型...基本的变量类型的储存空间被分配到栈中,而引用类型有两块储存空间,一块在栈中,一块在堆中,那...

    关于深入理解java的引用类型:

    在java中,引用类型可以分为两大类:值类型,引用类型。

    其中值类型就是基本数据类型,如int,double类型,而引用类型就是除了基本数据类型之外的所有类型(如class类型),所有的类型在内存中都会分匹配

    一定的空间,包括形参,而形参在方法调用完成后被分配的那块内存就会被取消,基本的变量类型的储存空间被分配到栈中,而引用类型有两块储存空间,

    一块在栈中,一块在堆中,那么在java中当函数调用的时候到底是传值还是传引用?

    在上图中引用类型在传参时不是在heap中再分配一块内存来存变量c 所指向的A(),而是让a 指向同一个A 的实例,这就与C++ 中的指针一样,先声明指针变量a,b,c,d 在传参的时候让a 指向c所指向的内存,让 d 指向 b 所指向的内存。很明显Java中的引用与C++中的指针在原理上是相类似的,但记住Java没有指针,只有引用。下面再通过一些具体的代码来讨论引用:

    1.简单类型是按值传递的

    Java 方法的参数是简单类型的时候,是按值传递的 (pass by value)。这一点我们可以通过一个简单的例子来说明:

    packagetest;public classTest {//交换两个变量的值

    public static void Swap(int a,intb){int c=a;

    a=b;

    b=c;

    System.out.println("a: "+a);

    System.out.println("b: "+b);

    }public static voidmain(String[] args){int c=10;int d=20;

    Swap(c,d);

    System.out.println("After Swap:");

    System.out.println("c: "+c);

    System.out.println("d: "+d);

    }

    }

    运行结果:

    a: 20

    b: 10

    After Swap:

    c: 10

    d: 20

    传值后数值交换失败,主方法打印数组中0,1元素数值后并没有改变

    原因:

    不难看出,虽然在 Swap (a,b) 方法中改变了传进来的参数的值,但对这个参数源变量本身并没有影响,即对 main(String[]) 方法里的 a,b 变量没有影响。那说明,参数类型是简单类型的时候,是按值传递的。以参数形式传递简单类型的变量时,实际上是将参数的值作了一个拷贝传进方法函数的,那么在方法函数里再怎么改变其值,其结果都是只改变了拷贝的值,而不是源值。

    public classMain{public static voidmain(String[] args) {int a = 10;int b = 20;//int tmp = 0;//tmp = a;//a = b;//b = tmp;//System.out.println("a:"+a+" b:"+b);

    swap(a,b);

    System.out.println("a:"+a+" b:"+b);

    }public static void swap(int a,intb){int tmp = 0;

    tmp=a;

    a=b;

    b=tmp;//System.out.println("a:"+a+" b:"+b);

    }

    }

    换成String类型也一样,交换只在主函数中或者方法中生效

    2.什么是引用

    Java 是传值还是传引用,问题主要出在对象的传递上,因为 Java 中简单类型没有引用。既然争论中提到了引用这个东西,为了搞清楚这个问题,我们必须要知道引用是什么。

    简单的说,引用其实就像是一个对象的名字或者别名 (alias),一个对象在内存中会请求一块空间来保存数据,根据对象的大小,它可能需要占用的空间大小也不等。访问对象的时候,我们不会直接是访问对象在内存中的数据,而是通过引用去访问。引用也是一种数据类型,我们可以把它想象为类似 C++ 语言中指针的东西,它指示了对象在内存中的地址——只不过我们不能够观察到这个地址究竟是什么。

    如果我们定义了不止一个引用指向同一个对象,那么这些引用是不相同的,因为引用也是一种数据类型,需要一定的内存空间(stack,栈空间)来保存。但是它们的值是相同的,都指示同一个对象在内存(heap,堆空间)的中位置。比如:

    String a="This is a Text!";

    String b=a;

    通过上面的代码和图形示例不难看出,a 和 b 是不同的两个引用,我们使用了两个定义语句来定义它们。但它们的值是一样的,都指向同一个对象 "This is a Text!"。但要注意String 对象的值本身是不可更改的 (像 b = "World"; b = a; 这种情况不是改变了 "World" 这一对象的值,而是改变了它的引用 b 的值使之指向了另一个 String 对象 a)。

    如图,开始b 的值为绿线所指向的“Word Two”,然后 b=a; 使 b 指向了红线所指向的”Word“.

    这里我描述了两个要点:

    (1) 引用是一种数据类型(保存在stack中),保存了对象在内存(heap,堆空间)中的地址,这种类型即不是我们平时所说的简单数据类型也不是类实例(对象);

    (2) 不同的引用可能指向同一个对象,换句话说,一个对象可以有多个引用,即该类类型的变量。

    3.对象是如何传递的呢

    随着学习的深入,你也许会对对象的传递方式产生疑问,即对象究竟是“按值传递”还是“按引用传递”?

    (1)认为是“按值传递”的:

    packagetest;public classTest {public static void Sample(inta){

    a+=20;

    System.out.println("a: "+a);

    }public static voidmain(String[] args){int b=10;

    Sample(b);

    System.out.println("b: "+b);

    }

    }

    运行结果:

    a: 30

    b: 10

    在这段代码里,修改变量 a 的值,不改变变量 b 的值,所以它是“值传递”。******************

    (2)认为是“按引用传递”的:

    public classMain{public static voidmain(String[] args) {

    String a= new String("hello"); //结果是hello world hello//StringBuffer a = new StringBuffer("hello");//结果是hello world hello world

    swap(a);

    System.out.println(a);

    }public static voidswap(String a){

    a+=" world";//a.append(" world");

    System.out.println(a);

    }

    }

    那么对象(记住在Java中一切皆对象,无论是int a;还是String a;,这两个变量a都是对象)在传递的时候究竟是按什么方式传递的呢?其答案就只能是:即是按值传递也是按引用传递,但通常基本数据类型(如int,double等)我们认为其是“值传递”,而自定义数据类型(class)我们认为其是“引用传递”。

    4. 正确看待传值还是传引用的问题

    要正确的看待这个问题必须要搞清楚为什么会有这样一个问题。

    实际上,问题来源于 C,而不是 Java。

    C语言中有一种数据类型叫做指针,于是将一个数据作为参数传递给某个函数的时候,就有两种方式:传值,或是传指针。 在值传递时,修改函数中的变量值不会改变原有变量的值,但是通过指针却会改变。

    void Swap(int a,int b){ int c=a;a=b;b=c;}void Swap(int *a,int *b){ int c=*a;*a=*b;*b=c; }int c=10;int d=20;

    Swap(c,d);//不改变 c , d 的值

    Swap(&c,&d); //改变 c , d 的值

    许多的 C 程序员开始转向学习 Java,他们发现,使用类似 SwapValue(T,T)(当T 为值类型时) 的方法仍然不能改变通过参数传递进来的简单数据类型的值,但是如果T时一个引用类型时,则可能将其成员随意更改。于是他们觉得这很像是 C 语言中传值/传指针的问题。但是 Java 中没有指针,那么这个问题就演变成了传值/传引用的问题。可惜将这个问题放在 Java 中进行讨论并不恰当。

    讨论这样一个问题的最终目的只是为了搞清楚何种情况才能在方法函数中方便的更改参数的值并使之长期有效。

    5.如何实现类似 swap 的方法

    传值还是传引用的问题,到此已经算是解决了,但是我们仍然不能解决这样一个问题:如果我有两个 int型的变量 a 和 b,我想写一个方法来交换它们的值,应该怎么办?有很多方法,这里介绍一种简单的方法(也可以在主函数中直接写交换):

    通过数组交换数值

    classTest {public static void swap(int[] d) {int c = d[0];

    d[0] = d[1];

    d[1] =c;

    System.out.println(d[0]);

    System.out.println(d[1]);

    }public static voidmain(String[] args) {int[] a = new int[2];

    a[0] = 10;

    a[1] = 20;

    swap(a);

    System.out.println("---------------");

    System.out.println(a[0]);

    System.out.println(a[1]);//下面的代码时编译不过的,形参中单东西在形参所在函数执行完毕后,便被java垃圾内存回收站回收了//此代码所做的事情,是通过上面形参函数交换实参里面数组内的两个值。//System.out.println(d[0]);//System.out.println(d[1]);

    }

    }

    public classTest {public static voidmain(String[] args) {int [] arr={1,2,3,4,5};

    System.out.println("交换值之前:"+Arrays.toString(arr));

    change(arr,1,3);

    System.out.println("交换值之后:"+Arrays.toString(arr));

    }public static void change(int []arr,int i,intj){int temp=arr[i];

    arr[i]=arr[j];

    arr[j]=temp;

    }

    }

    交换后结果:1 2 3 4 5

    1 4 3 2 5

    通过:对象的值的交换:

    classTe{int x=10;public Te(intx) {this.x =x;

    }

    }public classTest {public static voidmain(String[] args) {

    Te test=new Te(1);

    System.out.println("交换值之前:"+test.x);

    change(test,4);

    System.out.println("交换值之后:"+test.x);

    }public static void change(Te test,intx){

    test.x=x;

    }

    }

    执行结果:

    public classMain{public static voidmain(String[]args) {String a = newString("hello");

    // StringBuffer a = new StringBuffer("hello");swap(a);

    System.out.println(a);

    }public static voidswap(String a){a+=" world";

    // a.append(" world");System.out.println(a);

    }}

    展开全文
  • Java中一共4种引用类型(其实还有一些其他的引用类型比如FinalReference):强引用、软引用、弱引用、虚引用。其中强引用就是我们经常使用的 Objecta=newObject(); 这样的形式,在Java中并没有对应的Reference类。本...

    Java中一共有4种引用类型(其实还有一些其他的引用类型比如FinalReference):强引用、软引用、弱引用、虚引用。其中强引用就是我们经常使用的 Objecta=newObject(); 这样的形式,在Java中并没有对应的Reference类。

    本篇文章主要是分析软引用、弱引用、虚引用的实现,这三种引用类型都是继承于Reference这个类,主要逻辑也在Reference中。

    问题

    在分析前,先抛几个问题?

    1.网上大多数文章对于软引用的介绍是:在内存不足的时候才会被回收,那内存不足是怎么定义的?什么才叫内存不足?

    2.网上大多数文章对于虚引用的介绍是:形同虚设,虚引用并不会决定对象的生命周期。主要用来跟踪对象被垃圾回收器回收的活动。真的是这样吗?

    3.虚引用在Jdk中有哪些场景下用到了呢?

    Reference

    我们先看下 Reference.java中的几个字段

    一个Reference对象的生命周期如下:

    主要分为Native层和Java层两个部分。

    Native层在GC时将需要被回收的Reference对象加入到DiscoveredList中(代码在 referenceProcessor.cpp中 process_discovered_references方法),

    然后将DiscoveredList的元素移动到PendingList中

    (代码在 referenceProcessor.cpp中 enqueue_discovered_ref_helper方法),

    PendingList的队首就是Reference类中的pending对象。 具体代码就不分析了,有兴趣的同学可以看看这篇文章。

    看看Java层的代码

    流程比较简单:就是源源不断的从PendingList中提取出元素,然后将其加入到ReferenceQueue中去,开发者可以通过从ReferenceQueue中poll元素感知到对象被回收的事件。

    另外需要注意的是,对于Cleaner类型(继承自虚引用)的对象会有额外的处理:在其指向的对象被回收时,会调用clean方法,该方法主要是用来做对应的资源回收,在堆外内存DirectByteBuffer中就是用Cleaner进行堆外内存的回收,这也是虚引用在java中的典型应用。

    看完了Reference的实现,再看看几个实现类里,各自有什么不同。

    SoftReference

    软引用的实现很简单,就多了两个字段: clock和 timestamp。 clock是个静态变量,每次GC时都会将该字段设置成当前时间。 timestamp字段则会在每次调用get方法时将其赋值为 clock(如果不相等且对象没被回收)。

    那这两个字段的作用是什么呢?这和软引用在内存不够的时候才被回收,又有什么关系呢?

    这些还得看JVM的源码才行,因为决定对象是否需要被回收都是在GC中实现的。

    refs_lists中存放了本次GC发现的某种引用类型(虚引用、软引用、弱引用等),而 process_discovered_reflist方法的作用就是将不需要被回收的对象从 refs_lists移除掉, refs_lists最后剩下的元素全是需要被回收的元素,最后会将其第一个元素赋值给上文提到过的 Reference.java#pending字段。

    ReferencePolicy一共有4种实现:NeverClearPolicy,AlwaysClearPolicy,LRUCurrentHeapPolicy,LRUMaxHeapPolicy。其中NeverClearPolicy永远返回false,代表永远不回收SoftReference,在JVM中该类没有被使用,AlwaysClearPolicy则永远返回true,在 referenceProcessor.hpp#setup方法中中可以设置policy为AlwaysClearPolicy,至于什么时候会用到AlwaysClearPolicy,大家有兴趣可以自行研究。

    LRUCurrentHeapPolicy和LRUMaxHeapPolicy的shouldclearreference方法则是完全相同:

    timestmp_clock就是SoftReference的静态字段 clock, java_lang_ref_SoftReference::timestamp(p)对应是字段 timestamp。如果上次GC后有调用 SoftReference#get, interval值为0,否则为若干次GC之间的时间差。

    _max_interval则代表了一个临界值,它的值在LRUCurrentHeapPolicy和LRUMaxHeapPolicy两种策略中有差异。

    其中 SoftRefLRUPolicyMSPerMB默认为1000,前者的计算方法和上次GC后可用堆大小有关,后者计算方法和(堆大小-上次gc时堆使用大小)有关。

    看到这里你就知道SoftReference到底什么时候被被回收了,它和使用的策略(默认应该是LRUCurrentHeapPolicy),堆可用大小,该SoftReference上一次调用get方法的时间都有关系。

    WeakReference

    可以看到WeakReference在Java层只是继承了Reference,没有做任何的改动。那referent字段是什么时候被置为null的呢?要搞清楚这个问题我们再看下上文提到过的 process_discovered_reflist方法:

    不管是弱引用还是其他引用类型,将字段referent置null的操作都发生在 process_phase3中,而具体行为是由 clear_referent的值决定的。而 clear_referent的值则和引用类型相关。

    可以看到,对于Soft references和Weak references clear_referent字段传入的都是true,这也符合我们的预期:对象不可达后,引用字段就会被置为null,然后对象就会被回收(对于软引用来说,如果内存足够的话,在Phase 1,相关的引用就会从refslist中被移除,到Phase 3时refslist为空集合)。

    但对于Final references和 Phantom references, clear_referent字段传入的是false,也就意味着被这两种引用类型引用的对象,如果没有其他额外处理,只要Reference对象还存活,那引用的对象是不会被回收的。Final references和对象是否重写了finalize方法有关,不在本文分析范围之内,我们接下来看看Phantom references。

    PhantomReference

    可以看到虚引用的get方法永远返回null,我们看个demo。

    从以上代码中可以看到,虚引用能够在指向对象不可达时得到一个'通知'(其实所有继承References的类都有这个功能),需要注意的是GC完成后,phanRef.referent依然指向之前创建Object,也就是说Object对象一直没被回收!

    而造成这一现象的原因在上一小节末尾已经说了: 对于Finalreferences和Phantomreferences,clear_referent 字段传入的时false,也就意味着被这两种引用类型引用的对象,如果没有其他额外处理,在GC中是不会被回收的。

    对于虚引用来说,从 refQueue.remove();得到引用对象后,可以调用 clear方法强行解除引用和对象之间的关系,使得对象下次可以GC时可以被回收掉。

    End

    针对文章开头提出的几个问题,看完分析,我们已经能给出回答:

    1.我们经常在网上看到软引用的介绍是:在内存不足的时候才会回收,那内存不足是怎么定义的?为什么才叫内存不足?

    软引用会在内存不足时被回收,内存不足的定义和该引用对象get的时间以及当前堆可用内存大小都有关系,计算公式在上文中也已经给出。

    2.网上对于虚引用的介绍是:形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。主要用来跟踪对象被垃圾回收器回收的活动。真的是这样吗?

    严格的说,虚引用是会影响对象生命周期的,如果不做任何处理,只要虚引用不被回收,那其引用的对象永远不会被回收。所以一般来说,从ReferenceQueue中获得PhantomReference对象后,如果PhantomReference对象不会被回收的话(比如被其他GC ROOT可达的对象引用),需要调用 clear方法解除PhantomReference和其引用对象的引用关系。

    3.虚引用在Jdk中有哪些场景下用到了呢?

    DirectByteBuffer中是用虚引用的子类 Cleaner.java来实现堆外内存回收的,后续会写篇文章来说说堆外内存的里里外外。

    展开全文
  • 前言Java中一共4种引用类型(其实还有一些其他的引用类型比如FinalReference):强引用、软引用、弱引用、虚引用。其中强引用就是我们经常使用的Object a = new Object(); 这样的形式,在Java中并没有对应的...
    76505222263ed601af76d6b3da326b57.png

    前言

    Java中一共有4种引用类型(其实还有一些其他的引用类型比如FinalReference):强引用、软引用、弱引用、虚引用。其中强引用就是我们经常使用的Object a = new Object(); 这样的形式,在Java中并没有对应的Reference类。

    本篇文章主要是分析软引用、弱引用、虚引用的实现,这三种引用类型都是继承于Reference这个类,主要逻辑也在Reference中。

    问题

    在分析前,先抛几个问题?

    1.网上大多数文章对于软引用的介绍是:在内存不足的时候才会被回收,那内存不足是怎么定义的?什么才叫内存不足?

    2.网上大多数文章对于虚引用的介绍是:形同虚设,虚引用并不会决定对象的生命周期。主要用来跟踪对象被垃圾回收器回收的活动。真的是这样吗?

    3.虚引用在Jdk中有哪些场景下用到了呢?(文末有答案)

    Reference

    我们先看下Reference.java中的几个字段

    public abstract class Reference { //引用的对象 private T referent; //回收队列,由使用者在Reference的构造函数中指定 volatile ReferenceQueue super T> queue; //当该引用被加入到queue中的时候,该字段被设置为queue中的下一个元素,以形成链表结构 volatile Reference next; //在GC时,JVM底层会维护一个叫DiscoveredList的链表,存放的是Reference对象,discovered字段指向的就是链表中的下一个元素,由JVM设置 transient private Reference discovered; //进行线程同步的锁对象 static private class Lock { } private static Lock lock = new Lock();//等待加入queue的Reference对象,在GC时由JVM设置,会有一个java层的线程(ReferenceHandler)源源不断的从pending中提取元素加入到queue private static Reference pending = null;}

    一个Reference对象的生命周期如下:

    49104a10e765066dc765be34a7d19751.png

    主要分为Native层和Java层两个部分。

    Native层在GC时将需要被回收的Reference对象加入到DiscoveredList中(代码在referenceProcessor.cppprocess_discovered_references方法),然后将DiscoveredList的元素移动到PendingList中(代码在referenceProcessor.cppenqueue_discovered_ref_helper方法),PendingList的队首就是Reference类中的pending对象。

    看看Java层的代码

    private static class ReferenceHandler extends Thread { ... public void run() { while (true) { tryHandlePending(true); } } } static boolean tryHandlePending(boolean waitForNotify) { Reference r; Cleaner c; try { synchronized (lock) { if (pending != null) { r = pending; //如果是Cleaner对象,则记录下来,下面做特殊处理 c = r instanceof Cleaner ? (Cleaner) r : null; //指向PendingList的下一个对象 pending = r.discovered; r.discovered = null; } else { //如果pending为null就先等待,当有对象加入到PendingList中时,jvm会执行notify if (waitForNotify) { lock.wait(); } // retry if waited return waitForNotify; } } }  ... // 如果时CLeaner对象,则调用clean方法进行资源回收 if (c != null) { c.clean(); return true; }//将Reference加入到ReferenceQueue,开发者可以通过从ReferenceQueue中poll元素感知到对象被回收的事件。 ReferenceQueue super Object> q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); return true; }

    流程比较简单:就是源源不断的从PendingList中提取出元素,然后将其加入到ReferenceQueue中去,开发者可以通过从ReferenceQueue中poll元素感知到对象被回收的事件。

    另外需要注意的是,对于Cleaner类型(继承自虚引用)的对象会有额外的处理:在其指向的对象被回收时,会调用clean方法,该方法主要是用来做对应的资源回收,在堆外内存DirectByteBuffer中就是用Cleaner进行堆外内存的回收,这也是虚引用在java中的典型应用。

    看完了Reference的实现,再看看几个实现类里,各自有什么不同。

    SoftReference

    public class SoftReference extends Reference {  static private long clock;  private long timestamp;  public SoftReference(T referent) { super(referent); this.timestamp = clock; }  public SoftReference(T referent, ReferenceQueue super T> q) { super(referent, q); this.timestamp = clock; } public T get() { T o = super.get(); if (o != null && this.timestamp != clock) this.timestamp = clock; return o; }}

    软引用的实现很简单,就多了两个字段:clock和timestamp。clock是个静态变量,每次GC时都会将该字段设置成当前时间。timestamp字段则会在每次调用get方法时将其赋值为clock(如果不相等且对象没被回收)。

    那这两个字段的作用是什么呢?这和软引用在内存不够的时候才被回收,又有什么关系呢?

    这些还得看JVM的源码才行,因为决定对象是否需要被回收都是在GC中实现的。

    size_tReferenceProcessor::process_discovered_reflist( DiscoveredList refs_lists[], ReferencePolicy* policy, bool clear_referent, BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor){ ... //还记得上文提到过的DiscoveredList吗?refs_lists就是DiscoveredList。 //对于DiscoveredList的处理分为几个阶段,SoftReference的处理就在第一阶段 ... for (uint i = 0; i < _max_num_q; i++) { process_phase1(refs_lists[i], policy, is_alive, keep_alive, complete_gc); } ...}//该阶段的主要目的就是当内存足够时,将对应的SoftReference从refs_list中移除。voidReferenceProcessor::process_phase1(DiscoveredList& refs_list, ReferencePolicy* policy, BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc) {  DiscoveredListIterator iter(refs_list, keep_alive, is_alive); // Decide which softly reachable refs should be kept alive. while (iter.has_next()) { iter.load_ptrs(DEBUG_ONLY(!discovery_is_atomic() /* allow_null_referent */)); //判断引用的对象是否存活 bool referent_is_dead = (iter.referent() != NULL) && !iter.is_referent_alive(); //如果引用的对象已经不存活了,则会去调用对应的ReferencePolicy判断该对象是不时要被回收 if (referent_is_dead && !policy->should_clear_reference(iter.obj(), _soft_ref_timestamp_clock)) { if (TraceReferenceGC) { gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s" ") by policy
    展开全文
  • 引用类型 由类型的实际值引用(类似于指针)表示的数据类型。如果为某个变量分配一个引用类型,则该变量将引用(或“指向”)原始值。不创建任何副本。引用类型包括类、接口、委托和装箱值类型。Java中将引用分为四种:...
  • 在这四个引用类型中,只有强引用FinalReference类是包内可见,其他三种引用类型均为public,可以在应用程序中直接使用。引用类型的类结构如图所示。1.强引用Java中的引用,类似C语言中最难的指针。(我是C语言入门...
  • 引用与对象每种编程语言都自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java 中则是通过“引用”。在 Java 中一切都被视为了对象,但是我们操作的标识符实际上是对象的一个引用(reference)。//...
  • java中四种引用类型今天看代码,里面一个类java.lang.ref.SoftReference把小弟弄神了,试想一下,接触java已经3年了哇,连lang包下面的类都不了解,怎么混。后来在网上查资料,感觉收获颇多,现记录如下。对象的...
  • Java四种引用类型1.引用的基本概念强引用:当我们使用new创建对象时,被创建的对象就是强引用,如Object object = new Object(),其中的object就是一个强引用了。如果一个对象具有强引用,JVM就不会去GC它,JVM宁可...
  • 正如许多人或多或少正确地指出了引用和原始类型是什么一样,人们可能会对我们在Java中拥有更多相关的类型感兴趣。 这是java中类型的完整列表...Integer注意:基本类型和引用类型之间的差异使得必须依靠装箱转换对象...
  • 为什么需要引用Java的内存回收不需要程序员负责,JVM会在必要时启动Java GC完成垃圾回收。Java以便我们控制对象的...任何通过强引用所使用的对象不管系统资源多紧张,Java GC都不会主动回收具有强引用的对象。/...
  • 引用是Java面向对象的一个特点,在Java入门中,我们会接触到四种Java引用类型,具体包括这几个:1、强引用强引用是一种最常见的引用形式,同时也较为普遍。如果内存空间不足,Java虚拟机将会抛出OutOfMemoryError...
  • 文章非原创,引自 https://www.cnblogs.com/czx1/p/10665327.html一、值类型与引用类型 1、变量初始化int ...str是String引用类型变量,变量中保存的只是实际对象对应的地址信息,而不是实际对象数据。对于而这特...
  • 1. Java引用介绍Java从1.2版本开始引入了4种引用,这4种引用的级别由高到低依次为:强引用 > 软引用 > 弱引用 > 虚引用⑴ 强引用(Strong Reference)强引用是使用最普遍的引用,也是赋值的默认引用。如果一...
  • 简介Java中为了让程序员可以自己控制对象生命周期,提供了四种引用方式,都继承自java.lang.ref.Reference类,它们分别是:强引用、软引用、弱引用、虚引用。强引用(FinalReference / Finalizer)在Java中像Object ...
  • 什么叫引用referenceObject o = new Object();这个 o,我们可以称之为对象引用,而 new Object()我们可以称之为在内存 中产生了一个对象实例。当写下 o=null 时,只是表示 o 不再指向堆中 object 的对象实例,不代表这个...
  • 优质文章,及时送达Java中一共4种引用类型(其实还有一些其他的引用类型比如FinalReference):强引用、软引用、弱引用、虚引用。其中强引用就是我们经常使用的Object a = new Object; 这样的形式,在Java中并没有...
  • 每种编程语言都自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java 中则是通过“引用”。在 Java 中一切都被视为了对象,但是我们操作的标识符实际上是对象的一个引用(reference)。//创建一个...
  • 一次性给你总结:高频面试+学习笔记+思维导图等01 前言为了理解ThreadLocal,掌握引用的概念是非常必要的。02 引用与对象java中我们通过一个引用指向内存中对象。//创建一个引用引用可以独立存在,并...
  • 上一篇文章和大家分享了,JVM的入门内存执行顺序以及一些基础知识,今天和大家分享的是java引用类型。l 强引用(Strong Reference) ,即使多次gc回收,即使jvm内存已经不够用了,该引用继续抢占l 软引用(soft ...
  • Java中一共4种引用类型(其实还有一些其他的引用类型比如FinalReference):强引用、软引用、弱引用、虚引用。其中强引用就是我们经常使用的Object a = new Object(); 这样的形式,在Java中并没有对应的Reference类...
  • 我们知道在Java中除了基础的数据类型以外,其它的都为引用类型。 而Java根据其生命周期的长短将引用类型又分为 强引用、软引用、弱引用、幻象引用 。正常情况下我们平时基本上我们只用到强引用类型,而其他的引用...
  • 引用观察代码框下方的布局,可以看到两个按钮之下还有三个下拉菜单,依次点击之后本酱发现了一个神奇的选项:render all objects on the heap (Python/Java)。即图中红框处下拉菜单的第三个选项:这个...
  • 作者:瑞扬帆链接:https://blog.csdn.net/u012454924/article/details/77880367Java对象在Java虚拟机中的引用访问...下面我们详细了解在Java堆中的Java对象是如何访问定位的:先来了解reference类型数据是什么,再...
  • Java-String1. 导读String类也是日常开发中经常用到的类, 今天主要分享下我在看String源码时想到的4个问题:1.1 String为什么是不可变的; 为什么要设计成不可变的;1.2 hashCode; 为什么是31;2. String为什么是不可变...
  • 面试官爱问的一个基础问题:Java是值传递还是引用传递?想必大家都对这个问题都自己的看法,那到底事实是怎样的,我们又该如何回答面试官这个问题呢?今天咱们就来好好分析一波值传递?引用传递?首先,我们得先...
  • 四种引用类型1) 设立这些引用类型的目的定义Java对象重要性和优先级,提高JVM内存回收的执行效率。2) 强引用、软引用、弱引用和虚引用对比总结虚引用,配合引用队列使用,通过不断轮询引用队列获取对象回收事件。a) ...
  • ECMAScirpt 变量两种不同的数据类型:基本类型,引用类型。也其他的叫法,比如原始类型和对象类型,拥有方法的类型和不能拥有方法的类型,还可以分为可变类型和不可变类型,其实这些叫法都是依据这两种的类型...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 165
精华内容 66
关键字:

java引用类型有啥

java 订阅