/**
* -Xms10M -Xmx10M -XX:+PrintGC
*/publicclassSoftReferenceDemo{privatestaticList<SoftReference<Data>>softReferences=newArrayList<>();privatestaticReferenceQueuequeue=newReferenceQueue();privatestaticCountDownLatchcountDownLatch=newCountDownLatch(1);publicstaticvoidmain(String[]args)throwsInterruptedException{newSoftReferenceHandler().start();softReferenceTest();}privatestaticvoidsoftReferenceTest(){inti=0;while(i<8){Datadata=newData();SoftReference<Data>softData=newSoftReference<>(data,queue);System.out.printf("Add Data%s's SoftReference to list\n",data.hashCode());softReferences.add(softData);data=null;i++;}for(intj=0;j<softReferences.size();j++){System.out.printf("softReferences[%d] real Object is: %s\n",j,softReferences.get(j).get()==null?"null":"Data"+softReferences.get(j).get().hashCode());}countDownLatch.countDown();}privatestaticclassSoftReferenceHandlerextendsThread{@Overridepublicvoidrun(){try{countDownLatch.await();}catch(InterruptedExceptione){e.printStackTrace();}Referencereference;while(true){if((reference=queue.poll())!=null){System.out.printf("SoftReference%s has been unreachable\n",reference.hashCode());}}}}}classData{privatestaticfinalint_1M=1024*1024;privatefinalbyte[]data=newbyte[_1M];}
Add Data1956725890's SoftReference to list
Add Data692404036's SoftReference to list
Add Data1554874502's SoftReference to list
Add Data1846274136's SoftReference to list
Add Data1639705018's SoftReference to list
Add Data1627674070's SoftReference to list
Add Data1360875712's SoftReference to list
[GC (Allocation Failure) -- 8537K->8705K(9728K), 0.0010698 secs]
[Full GC (Ergonomics) 8705K->7971K(9728K), 0.0055837 secs]
[GC (Allocation Failure) -- 7971K->8011K(9728K), 0.0009023 secs]
[Full GC (Allocation Failure) 8011K->759K(9728K), 0.0136402 secs]
Add Data1625635731's SoftReference to list
softReferences[0] real Object is: null
softReferences[1] real Object is: null
softReferences[2] real Object is: null
softReferences[3] real Object is: null
softReferences[4] real Object is: null
softReferences[5] real Object is: null
softReferences[6] real Object is: null
softReferences[7] real Object is: Data1625635731
SoftReference901252740 has been unreachable
SoftReference830969067 has been unreachable
SoftReference1954876607 has been unreachable
SoftReference818067091 has been unreachable
SoftReference1161501225 has been unreachable
SoftReference1217855145 has been unreachable
SoftReference346747888 has been unreachable
//...// queue是作为WeakHashMap的字段,在Map创建实例时完成创建,每个Map实例都有自己的queueprivatefinalReferenceQueue<Object>queue=newReferenceQueue<>();// ...privatevoidexpungeStaleEntries(){// 从queue中获取GC过程加入到queue中的Entry,类比SoftReference示例中的queuefor(Objectx;(x=queue.poll())!=null;){synchronized(queue){@SuppressWarnings("unchecked")Entry<K,V>e=(Entry<K,V>)x;// 计算该Entry在哈希表中的位置inti=indexFor(e.hash,table.length);Entry<K,V>prev=table[i];Entry<K,V>p=prev;while(p!=null){Entry<K,V>next=p.next;// 由于Entry中的Key此时为null(待清理状态),因此此处使用==判断是否找到了该Entry,HaspMap中使用的是Key的equals方法if(p==e){// 找到后从链表中删除该Entry// 如果为头节点,则将头节点设为该节点的nextif(prev==e)table[i]=next;elseprev.next=next;// Must not null out e.next;// stale entries may be in use by a HashIterator// 清理value,断开value的强引用,以便value在下次GC时回收e.value=null;// Help GC// 修改sizesize--;break;}prev=p;p=next;}}}}
publicclassPhantomReference<T>extendsReference<T>{/**
* Returns this reference object's referent. Because the referent of a
* phantom reference is always inaccessible, this method always returns
* <code>null</code>.
*
* @return <code>null</code>
*/publicTget(){returnnull;}/**
* Creates a new phantom reference that refers to the given object and
* is registered with the given queue.
*
* <p> It is possible to create a phantom reference with a <tt>null</tt>
* queue, but such a reference is completely useless: Its <tt>get</tt>
* method will always return null and, since it does not have a queue, it
* will never be enqueued.
*
* @param referent the object the new phantom reference will refer to
* @param q the queue with which the reference is to be registered,
* or <tt>null</tt> if registration is not required
*/publicPhantomReference(Treferent,ReferenceQueue<?superT>q){super(referent,q);}}
可以发现,它的构造函数必须接收一个 ReferenceQueue 参数,且它的 get 方法永远返回 null(注意, PhantomReference 仍然持有一个 referent,只是它不对外公开)。
Note that whereas the garbage collector enqueues soft and weak reference objects when their referents are leaving the relevant reachability state, it enqueues phantom references when the referents are entering the relevant state. You can also see this difference in that the garbage collector clears soft and weak reference objects before enqueueing them, but not phantom reference objects. Thus, the garbage collector enqueues soft reference objects to indicate their referents have just left the softly reachable state. Likewise, the garbage collector enqueues weak reference objects to indicate their referents have just left the weakly reachable state. But the garbage collector enqueues phantom reference objects to indicate their referents have entered the phantom reachable state. Phantom reachable objects will remain phantom reachable until their reference objects are explicitly cleared by the program.
/* List of References waiting to be enqueued. The collector adds
* References to this list, while the Reference-handler thread removes
* them. This list is protected by the above lock object. The
* list uses the discovered field to link its elements.
*/privatestaticReference<Object>pending=null;
/* High-priority thread to enqueue pending References
*/privatestaticclassReferenceHandlerextendsThread{// ...ReferenceHandler(ThreadGroupg,Stringname){super(g,name);}publicvoidrun(){while(true){// 具体执行的任务tryHandlePending(true);}}}// ...static{ThreadGrouptg=Thread.currentThread().getThreadGroup();for(ThreadGrouptgn=tg;tgn!=null;tg=tgn,tgn=tg.getParent());Threadhandler=newReferenceHandler(tg,"Reference Handler");/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/handler.setPriority(Thread.MAX_PRIORITY);handler.setDaemon(true);handler.start();}
staticbooleantryHandlePending(booleanwaitForNotify){Reference<Object>r;Cleanerc;try{synchronized(lock){if(pending!=null){r=pending;// 'instanceof' might throw OutOfMemoryError sometimes // so do this before un-linking 'r' from the 'pending' chain... // 如果为Cleaner类型,则赋值给c c=rinstanceofCleaner?(Cleaner)r:null;// unlink 'r' from 'pending' chain pending=r.discovered;r.discovered=null;}else{// The waiting on the lock may cause an OutOfMemoryError // because it may try to allocate exception objects. if(waitForNotify){lock.wait();}// retry if waited returnwaitForNotify;}}}catch(OutOfMemoryErrorx){// Give other threads CPU time so they hopefully drop some live references // and GC reclaims some space. // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above // persistently throws OOME for some time... Thread.yield();// retry returntrue;}catch(InterruptedExceptionx){// retry returntrue;}// Fast path for cleaners if(c!=null){// c不为空,表示需要执行清理操作 c.clean();returntrue;}// 如果该引用对象的 queue 不为空,则执行入队操作 ReferenceQueue<?superObject>q=r.queue;if(q!=ReferenceQueue.NULL)q.enqueue(r);returntrue;}