下面列出了怎么用java.lang.ref.PhantomReference的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* 虚引用
* 虚引用用来跟踪对象被垃圾回收器回收的活动。虚引用和软引用与弱引用的区别在于虚引用必须和引用队列联合使用,
* 当虚引用被加入到引用队列的时候,说明这个对象已经被回收,可以在所引用的对象回收之后可以采取必要的行动。
*/
public static void main(String[] args) throws InterruptedException {
Object o = new Object();
// 必须结合引用队列
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
// 虚引用
PhantomReference<Object> phantomReference = new PhantomReference<>(o, referenceQueue);
System.out.println(o);
System.out.println(phantomReference.get());
System.out.println(referenceQueue.poll());
System.out.println("=================");
o = null;
System.gc();
Thread.sleep(500);
System.out.println(o);
System.out.println(phantomReference.get());
System.out.println(referenceQueue.poll());
}
public static void main(String[] args) {
String abc = new String("123");
ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
PhantomReference<String> ref = new PhantomReference<String>(abc,
referenceQueue);
abc = null;
System.gc();
//最好用Debug来调试
Object obj = referenceQueue.poll();
if (obj != null) {
Field rereferentVal = null;
try {
rereferentVal = Reference.class
.getDeclaredField("referent");
rereferentVal.setAccessible(true);
System.out.println("Before GC Clear:" + rereferentVal.get(obj).toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* This tests fills the cache with 64 KiB byte[] until it observes that the first one has been collected (via PhantomReference).
* It then verifies that this entry is also missing from the cache.
*/
@Test
public void testFillUntilClear() throws Exception {
SoftCache<String, byte[]> cache = new SoftCache<>();
byte[] element1 = new byte[64 * 1024];
String key1 = "element1";
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
PhantomReference<byte[]> watcher = new PhantomReference<>(element1, queue);
cache.checkin(key1, element1);
Assert.assertEquals(element1, cache.checkout(key1));
Assert.assertNull(cache.checkout(key1));
cache.checkin(key1, element1);
int i = 0;
while (watcher != queue.poll()) {
String key = "key_" + i;
byte[] value = new byte[64 * 1024];
cache.checkin(key, value);
i += 1;
}
Assert.assertNull(cache.checkout(key1));
}
@Override
public void run() {
while (true){
if(phantomQueue!=null){
PhantomReference<TraceCanReliveObj> objt=null;
try {
objt=(PhantomReference<TraceCanReliveObj>)phantomQueue.remove();
}catch (InterruptedException e){
e.fillInStackTrace();
}
if(objt!=null){
System.out.println("TraceCanReliveObj is delete");
}
}
}
}
public static void main(String[] args) throws InterruptedException{
Thread t=new CheckRefQueue();
t.setDaemon(true);
t.start();
phantomQueue=new ReferenceQueue<TraceCanReliveObj>();
obj=new TraceCanReliveObj();
PhantomReference<TraceCanReliveObj> phantomRef=new PhantomReference<TraceCanReliveObj>(obj,phantomQueue);
obj=null;
System.gc();
Thread.sleep(1000);
if(obj==null){
System.out.println("obj 是null");
}else {
System.out.println("obj 可用");
}
System.out.println("第二次gc");
obj=null;
System.gc();
Thread.sleep(1000);
if(obj==null){
System.out.println("obj是null");
}else {
System.out.println("obj 可用");
}
}
private Map<Object,Object> getWeakHashMap(Map<Object,Object> backingMap) {
/*
* Construct a weak hash map by copying the backingMap
* The backing map must be kept alive as long as the returned map is
* in scope, otherwise the contents will all end up garbage collected.
* Track the WeakhashMap using a PhantomReference queue, so that the
* backingmaps can be freed when the WeakHashMap has been GC.
*/
WeakHashMap<Object,Object> rv = new WeakHashMap<Object,Object>(backingMap);
PhantomReference<WeakHashMap<Object,Object>> ref =
new PhantomReference<WeakHashMap<Object,Object>>(rv, backingMapQueue);
synchronized(backingMaps){
backingMaps.put(ref, backingMap);
}
return rv;
}
/**
* Test that releasing the reference to the Cleaner service allows it to be
* be freed.
*/
@Test
void testCleanerTermination() {
ReferenceQueue<Object> queue = new ReferenceQueue<>();
Cleaner service = Cleaner.create();
PhantomReference<Object> ref = new PhantomReference<>(service, queue);
System.gc();
// Clear the Reference to the cleaning service and force a gc.
service = null;
System.gc();
try {
Reference<?> r = queue.remove(1000L);
Assert.assertNotNull(r, "queue.remove timeout,");
Assert.assertEquals(r, ref, "Wrong Reference dequeued");
} catch (InterruptedException ie) {
System.out.printf("queue.remove Interrupted%n");
}
}
/**
* Create a CleanableCase for a PhantomReference.
* @param cleaner the cleaner to use
* @param obj an object or null to create a new Object
* @return a new CleanableCase preset with the object, cleanup, and semaphore
*/
static CleanableCase setupPhantomSubclassException(Cleaner cleaner, Object obj) {
if (obj == null) {
obj = new Object();
}
Semaphore s1 = new Semaphore(0);
Cleaner.Cleanable c1 = new PhantomCleanable<Object>(obj, cleaner) {
protected void performCleanup() {
s1.release();
throw new RuntimeException("Exception thrown to cleaner thread");
}
};
return new CleanableCase(new PhantomReference<>(obj, null), c1, s1, true);
}
public ElasticsearchStore(String hostname, int port, String clusterName, String index, boolean cacheEnabled) {
super(cacheEnabled);
this.hostname = hostname;
this.port = port;
this.clusterName = clusterName;
this.index = index;
clientProvider = new SingletonClientProvider(hostname, port, clusterName);
dataStructure = new ElasticsearchDataStructure(clientProvider, index);
namespaceStore = new ElasticsearchNamespaceStore(clientProvider, index + "_namespaces");
ReferenceQueue<ElasticsearchStore> objectReferenceQueue = new ReferenceQueue<>();
startGarbageCollectionMonitoring(objectReferenceQueue, new PhantomReference<>(this, objectReferenceQueue),
clientProvider);
}
@Override
public void run() {
while (true){
if(phantomQueue!=null){
PhantomReference<TraceCanReliveObj> objt=null;
try {
objt=(PhantomReference<TraceCanReliveObj>)phantomQueue.remove();
}catch (InterruptedException e){
e.fillInStackTrace();
}
if(objt!=null){
System.out.println("TraceCanReliveObj is delete");
}
}
}
}
public static void main(String[] args) throws InterruptedException{
Thread t=new CheckRefQueue();
t.setDaemon(true);
t.start();
phantomQueue=new ReferenceQueue<TraceCanReliveObj>();
obj=new TraceCanReliveObj();
PhantomReference<TraceCanReliveObj> phantomRef=new PhantomReference<TraceCanReliveObj>(obj,phantomQueue);
obj=null;
System.gc();
Thread.sleep(1000);
if(obj==null){
System.out.println("obj 是null");
}else {
System.out.println("obj 可用");
}
System.out.println("第二次gc");
obj=null;
System.gc();
Thread.sleep(1000);
if(obj==null){
System.out.println("obj是null");
}else {
System.out.println("obj 可用");
}
}
/**
* Constructs a new queue.
*/
public FinalizableReferenceQueue() {
// We could start the finalizer lazily, but I'd rather it blow up early.
queue = new ReferenceQueue<Object>();
frqRef = new PhantomReference<Object>(this, queue);
boolean threadStarted = false;
try {
startFinalizer.invoke(null, FinalizableReference.class, queue, frqRef);
threadStarted = true;
} catch (IllegalAccessException impossible) {
throw new AssertionError(impossible); // startFinalizer() is public
} catch (Throwable t) {
logger.log(
Level.INFO,
"Failed to start reference finalizer thread."
+ " Reference cleanup will only occur when new references are created.",
t);
}
this.threadStarted = threadStarted;
}
/**
* Constructs a new queue.
*/
public FinalizableReferenceQueue() {
// We could start the finalizer lazily, but I'd rather it blow up early.
queue = new ReferenceQueue<Object>();
frqRef = new PhantomReference<Object>(this, queue);
boolean threadStarted = false;
try {
startFinalizer.invoke(null, FinalizableReference.class, queue, frqRef);
threadStarted = true;
} catch (IllegalAccessException impossible) {
throw new AssertionError(impossible); // startFinalizer() is public
} catch (Throwable t) {
logger.log(
Level.INFO,
"Failed to start reference finalizer thread."
+ " Reference cleanup will only occur when new references are created.",
t);
}
this.threadStarted = threadStarted;
}
/**
* Constructs a new queue.
*/
public FinalizableReferenceQueue() {
// We could start the finalizer lazily, but I'd rather it blow up early.
queue = new ReferenceQueue<Object>();
frqRef = new PhantomReference<Object>(this, queue);
boolean threadStarted = false;
try {
startFinalizer.invoke(null, FinalizableReference.class, queue, frqRef);
threadStarted = true;
} catch (IllegalAccessException impossible) {
throw new AssertionError(impossible); // startFinalizer() is public
} catch (Throwable t) {
logger.log(
Level.INFO,
"Failed to start reference finalizer thread."
+ " Reference cleanup will only occur when new references are created.",
t);
}
this.threadStarted = threadStarted;
}
/**
* Constructs a new queue.
*/
public FinalizableReferenceQueue() {
// We could start the finalizer lazily, but I'd rather it blow up early.
queue = new ReferenceQueue<Object>();
frqRef = new PhantomReference<Object>(this, queue);
boolean threadStarted = false;
try {
startFinalizer.invoke(null, FinalizableReference.class, queue, frqRef);
threadStarted = true;
} catch (IllegalAccessException impossible) {
throw new AssertionError(impossible); // startFinalizer() is public
} catch (Throwable t) {
logger.log(Level.INFO,
"Failed to start reference finalizer thread." + " Reference cleanup will only occur when new references are created.", t);
}
this.threadStarted = threadStarted;
}
/**
* Constructs a new queue.
*/
public FinalizableReferenceQueue() {
// We could start the finalizer lazily, but I'd rather it blow up early.
queue = new ReferenceQueue<Object>();
frqRef = new PhantomReference<Object>(this, queue);
boolean threadStarted = false;
try {
startFinalizer.invoke(null, FinalizableReference.class, queue, frqRef);
threadStarted = true;
} catch (IllegalAccessException impossible) {
throw new AssertionError(impossible); // startFinalizer() is public
} catch (Throwable t) {
logger.log(
Level.INFO,
"Failed to start reference finalizer thread."
+ " Reference cleanup will only occur when new references are created.",
t);
}
this.threadStarted = threadStarted;
}
/**
* Constructs a new queue.
*/
public FinalizableReferenceQueue() {
// We could start the finalizer lazily, but I'd rather it blow up early.
queue = new ReferenceQueue<Object>();
frqRef = new PhantomReference<Object>(this, queue);
boolean threadStarted = false;
try {
startFinalizer.invoke(null, FinalizableReference.class, queue, frqRef);
threadStarted = true;
} catch (IllegalAccessException impossible) {
throw new AssertionError(impossible); // startFinalizer() is public
} catch (Throwable t) {
logger.log(
Level.INFO,
"Failed to start reference finalizer thread."
+ " Reference cleanup will only occur when new references are created.",
t);
}
this.threadStarted = threadStarted;
}
/**
* Allocates a byte buffer of the given size.
* <p>
* This {@code BufferSource} places no restrictions on the requested size of
* the buffer.
*/
@Override
public Page allocate(int size, boolean thief, boolean victim, OffHeapStorageArea owner) {
while (true) {
processQueue();
long now = max.get();
if (now < size) {
return null;
} else if (max.compareAndSet(now, now - size)) {
ByteBuffer buffer;
try {
buffer = ByteBuffer.allocateDirect(size);
} catch (OutOfMemoryError e) {
return null;
}
bufferSizes.put(new PhantomReference<>(buffer, allocatedBuffers), size);
return new Page(buffer, owner);
}
}
}
public static PhantomReference<ClassLoader> loadAndRun(Path jarFilePath)
throws Exception {
ClassLoader classLoader = new URLClassLoader(
new URL[]{jarFilePath.toUri().toURL()}) {
@Override public String toString() { return "LeakedClassLoader"; }
};
Class<?> loadClass = Class.forName("ClassForName", true, classLoader);
((Runnable) loadClass.newInstance()).run();
PhantomReference<ClassLoader> ref = new PhantomReference<>(classLoader, rq);
System.out.println("returning phantom ref: " + ref + " to " + classLoader);
return ref;
}
public static void main(String[] args) {
String obj = new String("123");
ReferenceQueue<String> refQueue = new ReferenceQueue<String>();
PhantomReference<String> phantom = new PhantomReference<String>(obj,
refQueue);
System.out.println(phantom);
// 调用phanRef.get()不管在什么情况下会一直返回null
System.out.println(phantom.get());
}
public static PhantomReference<ClassLoader> loadAndRun(Path jarFilePath)
throws Exception {
ClassLoader classLoader = new URLClassLoader(
new URL[]{jarFilePath.toUri().toURL()}) {
@Override public String toString() { return "LeakedClassLoader"; }
};
Class<?> loadClass = Class.forName("ClassForName", true, classLoader);
((Runnable) loadClass.newInstance()).run();
PhantomReference<ClassLoader> ref = new PhantomReference<>(classLoader, rq);
System.out.println("returning phantom ref: " + ref + " to " + classLoader);
return ref;
}
public static void main(String args[]) throws InterruptedException {
helper.startTime();
List<PhantomReference<Monkey>> list = helper.getFilledList();
//before GC
helper.checkListWithReferences(list, "before");
helper.callGC();
helper.heapConsuming();
//after GC
helper.checkListWithReferences(list, "after");
helper.finish();
}
public void checkListWithReferences(List<PhantomReference<Monkey>> list, String string) {
int count = 0;
for (PhantomReference<Monkey> reference : list) {
if (reference.isEnqueued()) {
count++;
}
}
System.out.println(String.format("The enqueue reference count is %d (%s GC was called)", count, string));
}
public List<PhantomReference<Monkey>> getFilledList() {
//список призрачных ссылок
ArrayList<PhantomReference<Monkey>> list = new ArrayList<PhantomReference<Monkey>>();
//создаем 200 объектов и добавляем их в список через призрачные ссылки
for ( int i = 0; i < 200; i++) {
Monkey monkey = new Monkey();
list.add(new PhantomReference (monkey, queue));
}
return list;
}
/**
* Performs the actual registration of the target object to be disposed.
* @param target Object to be registered, or if target is an instance
* of DisposerTarget, its associated disposer referent
* will be the Object that is registered
* @param rec the associated DisposerRecord object
* @see DisposerRecord
*/
synchronized void add(Object target, DisposerRecord rec) {
if (target instanceof DisposerTarget) {
target = ((DisposerTarget)target).getDisposerReferent();
}
java.lang.ref.Reference<Object> ref;
if (refType == PHANTOM) {
ref = new PhantomReference<>(target, queue);
} else {
ref = new WeakReference<>(target, queue);
}
records.put(ref, rec);
}
public static void main(String[] args) throws Exception {
mh = NonInlinedReinvoker.make(
LOOKUP.findStatic(T.class, "f1", MethodType.methodType(int.class)));
// Monitor LambdaForm GC
lform = new PhantomReference<>(MethodHandleHelper.getLambdaForm(mh), rq);
test(0);
WB.clearInlineCaches();
test(0);
mh = NonInlinedReinvoker.make(
LOOKUP.findStatic(T.class, "f2", MethodType.methodType(int.class)));
Reference<?> ref = null;
while (ref == null) {
WB.fullGC();
try {
ref = rq.remove(1000);
} catch (InterruptedException e) { /*ignore*/ }
}
test(1);
WB.clearInlineCaches();
test(1);
System.out.println("TEST PASSED");
}
/**
* Performs the actual registration of the target object to be disposed.
* @param target Object to be registered, or if target is an instance
* of DisposerTarget, its associated disposer referent
* will be the Object that is registered
* @param rec the associated DisposerRecord object
* @see DisposerRecord
*/
synchronized void add(Object target, DisposerRecord rec) {
if (target instanceof DisposerTarget) {
target = ((DisposerTarget)target).getDisposerReferent();
}
java.lang.ref.Reference<Object> ref;
if (refType == PHANTOM) {
ref = new PhantomReference<>(target, queue);
} else {
ref = new WeakReference<>(target, queue);
}
records.put(ref, rec);
}
public static PhantomReference<ClassLoader> loadAndRun(Path jarFilePath)
throws Exception {
ClassLoader classLoader = new URLClassLoader(
new URL[]{jarFilePath.toUri().toURL()}) {
@Override public String toString() { return "LeakedClassLoader"; }
};
Class<?> loadClass = Class.forName("ClassForName", true, classLoader);
((Runnable) loadClass.newInstance()).run();
PhantomReference<ClassLoader> ref = new PhantomReference<>(classLoader, rq);
System.out.println("returning phantom ref: " + ref + " to " + classLoader);
return ref;
}
/**
* Create a CleanableCase for a PhantomReference.
* @param cleaner the cleaner to use
* @param obj an object or null to create a new Object
* @return a new CleanableCase preset with the object, cleanup, and semaphore
*/
static CleanableCase setupPhantom(Cleaner cleaner, Object obj) {
if (obj == null) {
obj = new Object();
}
Semaphore s1 = new Semaphore(0);
Cleaner.Cleanable c1 = cleaner.register(obj, () -> s1.release());
return new CleanableCase(new PhantomReference<>(obj, null), c1, s1);
}
/**
* Create a CleanableCase for a PhantomReference.
* @param cleaner the cleaner to use
* @param obj an object or null to create a new Object
* @return a new CleanableCase preset with the object, cleanup, and semaphore
*/
static CleanableCase setupPhantomSubclass(Cleaner cleaner, Object obj) {
if (obj == null) {
obj = new Object();
}
Semaphore s1 = new Semaphore(0);
Cleaner.Cleanable c1 = new PhantomCleanable<Object>(obj, cleaner) {
protected void performCleanup() {
s1.release();
}
};
return new CleanableCase(new PhantomReference<>(obj, null), c1, s1);
}