1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package java.lang.ref; 18 19 /** 20 * @hide 21 */ 22 public final class FinalizerReference<T> extends Reference<T> { 23 // This queue contains those objects eligible for finalization. 24 public static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); 25 26 // Guards the list (not the queue). 27 private static final Object LIST_LOCK = new Object(); 28 29 // This list contains a FinalizerReference for every finalizable object in the heap. 30 // Objects in this list may or may not be eligible for finalization yet. 31 private static FinalizerReference<?> head = null; 32 33 // The links used to construct the list. 34 private FinalizerReference<?> prev; 35 private FinalizerReference<?> next; 36 37 // When the GC wants something finalized, it moves it from the 'referent' field to 38 // the 'zombie' field instead. 39 private T zombie; 40 41 public FinalizerReference(T r, ReferenceQueue<? super T> q) { 42 super(r, q); 43 } 44 45 @Override public T get() { 46 return zombie; 47 } 48 49 @Override public void clear() { 50 zombie = null; 51 } 52 53 public static void add(Object referent) { 54 FinalizerReference<?> reference = new FinalizerReference<Object>(referent, queue); 55 synchronized (LIST_LOCK) { 56 reference.prev = null; 57 reference.next = head; 58 if (head != null) { 59 head.prev = reference; 60 } 61 head = reference; 62 } 63 } 64 65 public static void remove(FinalizerReference<?> reference) { 66 synchronized (LIST_LOCK) { 67 FinalizerReference<?> next = reference.next; 68 FinalizerReference<?> prev = reference.prev; 69 reference.next = null; 70 reference.prev = null; 71 if (prev != null) { 72 prev.next = next; 73 } else { 74 head = next; 75 } 76 if (next != null) { 77 next.prev = prev; 78 } 79 } 80 } 81 82 /** 83 * Waits for all currently-enqueued references to be finalized. 84 */ 85 public static void finalizeAllEnqueued(long timeout) throws InterruptedException { 86 // Alloate a new sentinel, this creates a FinalizerReference. 87 Sentinel sentinel; 88 // Keep looping until we safely enqueue our sentinel FinalizerReference. 89 // This is done to prevent races where the GC updates the pendingNext 90 // before we get the chance. 91 do { 92 sentinel = new Sentinel(); 93 } while (!enqueueSentinelReference(sentinel)); 94 sentinel.awaitFinalization(timeout); 95 } 96 97 private static boolean enqueueSentinelReference(Sentinel sentinel) { 98 synchronized (LIST_LOCK) { 99 // When a finalizable object is allocated, a FinalizerReference is added to the list. 100 // We search the list for that FinalizerReference (it should be at or near the head), 101 // and then put it on the queue so that it can be finalized. 102 for (FinalizerReference<?> r = head; r != null; r = r.next) { 103 if (r.referent == sentinel) { 104 FinalizerReference<Sentinel> sentinelReference = (FinalizerReference<Sentinel>) r; 105 sentinelReference.referent = null; 106 sentinelReference.zombie = sentinel; 107 // Make a single element list, then enqueue the reference on the daemon unenqueued 108 // list. This is required instead of enqueuing directly on the finalizer queue 109 // since there could be recently freed objects in the unqueued list which are not 110 // yet on the finalizer queue. This could cause the sentinel to run before the 111 // objects are finalized. b/17381967 112 // Make circular list if unenqueued goes through native so that we can prevent 113 // races where the GC updates the pendingNext before we do. If it is non null, then 114 // we update the pending next to make a circular list while holding a lock. 115 // b/17462553 116 if (!sentinelReference.makeCircularListIfUnenqueued()) { 117 return false; 118 } 119 ReferenceQueue.add(sentinelReference); 120 return true; 121 } 122 } 123 } 124 // We just created a finalizable object and still hold a reference to it. 125 // It must be on the list. 126 throw new AssertionError("newly-created live Sentinel not on list!"); 127 } 128 129 private native boolean makeCircularListIfUnenqueued(); 130 131 /** 132 * A marker object that we can immediately enqueue. When this object's 133 * finalize() method is called, we know all previously-enqueued finalizable 134 * references have been finalized. 135 */ 136 private static class Sentinel { 137 boolean finalized = false; 138 139 @Override protected synchronized void finalize() throws Throwable { 140 if (finalized) { 141 throw new AssertionError(); 142 } 143 finalized = true; 144 notifyAll(); 145 } 146 147 synchronized void awaitFinalization(long timeout) throws InterruptedException { 148 final long startTime = System.nanoTime(); 149 final long endTime = startTime + timeout; 150 while (!finalized) { 151 // 0 signifies no timeout. 152 if (timeout != 0) { 153 final long currentTime = System.nanoTime(); 154 if (currentTime >= endTime) { 155 break; 156 } else { 157 final long deltaTime = endTime - currentTime; 158 wait(deltaTime / 1000000, (int)(deltaTime % 1000000)); 159 } 160 } else { 161 wait(); 162 } 163 } 164 } 165 } 166 } 167