FinalizerReference 笔记

做内存泄漏分析时,总是可以在HeapDump中看到这么一个类:FinalizerReference

数量很多,而且Retained Size还不小,那么他是内存泄漏的标志么?

FinalizerReference 笔记_第1张图片
image.png
template
inline Object* Class::Alloc(Thread* self, gc::AllocatorType allocator_type) {
  CheckObjectAlloc();
  gc::Heap* heap = Runtime::Current()->GetHeap();
  const bool add_finalizer = kCheckAddFinalizer && IsFinalizable();
  if (!kCheckAddFinalizer) {
    DCHECK(!IsFinalizable());
  }
  mirror::Object* obj =
      heap->AllocObjectWithAllocator(self, this, this->object_size_,
                                                             allocator_type, VoidFunctor());
  if (add_finalizer && LIKELY(obj != nullptr)) {
    heap->AddFinalizerReference(self, &obj);
    if (UNLIKELY(self->IsExceptionPending())) {
      // Failed to allocate finalizer reference, it means that the whole allocation failed.
      obj = nullptr;
    }
  }
  return obj;
}

在Java堆中创建对象时,如果发现class定义了finalize这个方法,那么就会新建一个FinalizerReference,指向这个新建的对象。

void Heap::AddFinalizerReference(Thread* self, mirror::Object** object) {
  ScopedObjectAccess soa(self);
  ScopedLocalRef arg(self->GetJniEnv(), soa.AddLocalReference(*object));
  jvalue args[1];
  args[0].l = arg.get();
  InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_FinalizerReference_add, args);
  // Restore object in case it gets moved.
  *object = soa.Decode(arg.get());
}

其中会调用Java中FinalizerReference的静态方法add, 方法中会创建一个FinalizerRefence对象,同时链入FinalizerReferencehead变量指向的静态链表中

    public static void add(Object referent) {
        FinalizerReference reference = new FinalizerReference(referent, queue);
        synchronized (LIST_LOCK) {
            reference.prev = null;
            reference.next = head;
            if (head != null) {
                head.prev = reference;
            }
            head = reference;
        }
    }
 
 

在对象被回收后,会调用ReferenceProcessorDelayReferenceReferent将FinalizerRefence放入finalizer_reference_queue_队列中

void ReferenceProcessor::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref,
                                                collector::GarbageCollector* collector) {
  // klass can be the class of the old object if the visitor already updated the class of ref.
  DCHECK(klass != nullptr);
  DCHECK(klass->IsTypeOfReferenceClass());
  mirror::HeapReference* referent = ref->GetReferentReferenceAddr();
  if (referent->AsMirrorPtr() != nullptr && !collector->IsMarkedHeapReference(referent)) {
    Thread* self = Thread::Current();
    // TODO: Remove these locks, and use atomic stacks for storing references?
    // We need to check that the references haven't already been enqueued since we can end up
    // scanning the same reference multiple times due to dirty cards.
    if (klass->IsSoftReferenceClass()) {
      soft_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
    } else if (klass->IsWeakReferenceClass()) {
      weak_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
    } else if (klass->IsFinalizerReferenceClass()) {
      finalizer_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
    } else if (klass->IsPhantomReferenceClass()) {
      phantom_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
    } else {
      LOG(FATAL) << "Invalid reference type " << PrettyClass(klass) << " " << std::hex
                 << klass->GetAccessFlags();
    }
  }
}

ReferenceProcessorProcessReferences中会调用finalizer_reference_queue_EnqueueFinalizerReferences方法

void ReferenceProcessor::ProcessReferences(bool concurrent, TimingLogger* timings,
                                           bool clear_soft_references,
                                           collector::GarbageCollector* collector) {
  TimingLogger::ScopedTiming t(concurrent ? __FUNCTION__ : "(Paused)ProcessReferences", timings);
  Thread* self = Thread::Current();
  {
    ....
    // Preserve all white objects with finalize methods and schedule them for finalization.
    finalizer_reference_queue_.EnqueueFinalizerReferences(&cleared_references_, collector);
    ......
  }

EnqueueFinalizerReferences方法中会从队列中依次取出等待处理的FinalizerRefence,然后将FinalizerRefencereferent置为空,将指向的对象设置到zombiefield中,同时将FinalizerRefence放入cleared_references

void ReferenceQueue::EnqueueFinalizerReferences(ReferenceQueue* cleared_references,
                                                collector::GarbageCollector* collector) {
  while (!IsEmpty()) {
    mirror::FinalizerReference* ref = DequeuePendingReference()->AsFinalizerReference();
    mirror::HeapReference* referent_addr = ref->GetReferentReferenceAddr();
    if (referent_addr->AsMirrorPtr() != nullptr &&
        !collector->IsMarkedHeapReference(referent_addr)) {
      mirror::Object* forward_address = collector->MarkObject(referent_addr->AsMirrorPtr());
      // Move the updated referent to the zombie field.
      if (Runtime::Current()->IsActiveTransaction()) {
        ref->SetZombie(forward_address);
        ref->ClearReferent();
      } else {
        ref->SetZombie(forward_address);
        ref->ClearReferent();
      }
      cleared_references->EnqueueReference(ref);
    }
  }
}

ClearedReferenceTask中会将cleared_references_中的reference通过Java中ReferenceQueue.add方法添加到Java ReferenceQueue的unenqueued队列中

class ClearedReferenceTask : public HeapTask {
 public:
  explicit ClearedReferenceTask(jobject cleared_references)
      : HeapTask(NanoTime()), cleared_references_(cleared_references) {
  }
  virtual void Run(Thread* thread) {
    ScopedObjectAccess soa(thread);
    jvalue args[1];
    args[0].l = cleared_references_;
    InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_ReferenceQueue_add, args);
    soa.Env()->DeleteGlobalRef(cleared_references_);
  }

 private:
  const jobject cleared_references_;
};

ReferenceQueue.java

    public static Reference unenqueued = null;

    static void add(Reference list) {
        synchronized (ReferenceQueue.class) {
            if (unenqueued == null) {
                unenqueued = list;
            } else {
                // Find the last element in unenqueued.
                Reference last = unenqueued;
                while (last.pendingNext != unenqueued) {
                  last = last.pendingNext;
                }
                // Add our list to the end. Update the pendingNext to point back to enqueued.
                last.pendingNext = list;
                last = list;
                while (last.pendingNext != list) {
                    last = last.pendingNext;
                }
                last.pendingNext = unenqueued;
            }
            ReferenceQueue.class.notifyAll();
        }
    }

虚拟机在Java层会启动三个daemon线程


public final class Daemons {

    public static void start() {
        ReferenceQueueDaemon.INSTANCE.start(); //将unqueued链表中的Reference放入对用的ReferenceQueue中
        FinalizerDaemon.INSTANCE.start();  //将FinalizerRefenceQueue中的对象调用finalize方法
        FinalizerWatchdogDaemon.INSTANCE.start(); //防止finalize方法调用时间过长
        HeapTaskDaemon.INSTANCE.start();
    }
}

先看ReferenceQueueDaemonrun方法

    private static class ReferenceQueueDaemon extends Daemon {
        private static final ReferenceQueueDaemon INSTANCE = new ReferenceQueueDaemon();

        ReferenceQueueDaemon() {
            super("ReferenceQueueDaemon");
        }

        @Override public void run() {
            while (isRunning()) {
                Reference list;
                try {
                    synchronized (ReferenceQueue.class) {
                        while (ReferenceQueue.unenqueued == null) {
                            ReferenceQueue.class.wait();
                        }
                        list = ReferenceQueue.unenqueued;
                        ReferenceQueue.unenqueued = null;
                    }
                } catch (InterruptedException e) {
                    continue;
                } catch (OutOfMemoryError e) {
                    continue;
                }
                ReferenceQueue.enqueuePending(list);
            }
        }
    }

ReferenceQueue.unenqueued中的Reference调用ReferenceQueue.enqueuePending方法

ReferenceQueue.java

    public static void enqueuePending(Reference list) {
        Reference start = list;
        do {
            ReferenceQueue queue = list.queue;
            if (queue == null) {
                Reference next = list.pendingNext;

                // Make pendingNext a self-loop to preserve the invariant that
                // once enqueued, pendingNext is non-null -- without leaking
                // the object pendingNext was previously pointing to.
                list.pendingNext = list;
                list = next;
            } else {
                // To improve performance, we try to avoid repeated
                // synchronization on the same queue by batching enqueue of
                // consecutive references in the list that have the same
                // queue.
                synchronized (queue.lock) {
                    do {
                        Reference next = list.pendingNext;

                        // Make pendingNext a self-loop to preserve the
                        // invariant that once enqueued, pendingNext is
                        // non-null -- without leaking the object pendingNext
                        // was previously pointing to.
                        list.pendingNext = list;
                        queue.enqueueLocked(list);
                        list = next;
                    } while (list != start && list.queue == queue);
                    queue.lock.notifyAll();
                }
            }
        } while (list != start);
    }

将Reference放入对应的ReferenceQueue中去。所以对于SoftReference和WeakReference来说,进入ReferenceQueue就说明被回收了。LeakCanary就是通过WeakReferenceQueue来检测对象是否回收以判断是否内存泄漏的

对于FinalizerRefence来说,还没有完

    private static class FinalizerDaemon extends Daemon {
        private static final FinalizerDaemon INSTANCE = new FinalizerDaemon();
        private final ReferenceQueue queue = FinalizerReference.queue;
        private final AtomicInteger progressCounter = new AtomicInteger(0);
        // Object (not reference!) being finalized. Accesses may race!
        private Object finalizingObject = null;

        FinalizerDaemon() {
            super("FinalizerDaemon");
        }

        @Override public void run() {
            // This loop may be performance critical, since we need to keep up with mutator
            // generation of finalizable objects.
            // We minimize the amount of work we do per finalizable object. For example, we avoid
            // reading the current time here, since that involves a kernel call per object.  We
            // limit fast path communication with FinalizerWatchDogDaemon to what's unavoidable: A
            // non-volatile store to communicate the current finalizable object, e.g. for
            // reporting, and a release store (lazySet) to a counter.
            // We do stop the  FinalizerWatchDogDaemon if we have nothing to do for a
            // potentially extended period.  This prevents the device from waking up regularly
            // during idle times.

            // Local copy of progressCounter; saves a fence per increment on ARM and MIPS.
            int localProgressCounter = progressCounter.get();

            while (isRunning()) {
                try {
                    // Use non-blocking poll to avoid FinalizerWatchdogDaemon communication
                    // when busy.
                    FinalizerReference finalizingReference = (FinalizerReference)queue.poll();
                    if (finalizingReference != null) {
                        finalizingObject = finalizingReference.get();
                        progressCounter.lazySet(++localProgressCounter);
                    } else {
                        finalizingObject = null;
                        progressCounter.lazySet(++localProgressCounter);
                        // Slow path; block.
                        FinalizerWatchdogDaemon.INSTANCE.goToSleep();
                        finalizingReference = (FinalizerReference)queue.remove();
                        finalizingObject = finalizingReference.get();
                        progressCounter.set(++localProgressCounter);
                        FinalizerWatchdogDaemon.INSTANCE.wakeUp();
                    }
                    doFinalize(finalizingReference);
                } catch (InterruptedException ignored) {
                } catch (OutOfMemoryError ignored) {
                }
            }
        }

        @FindBugsSuppressWarnings("FI_EXPLICIT_INVOCATION")
        private void doFinalize(FinalizerReference reference) {
            FinalizerReference.remove(reference);
            Object object = reference.get();
            reference.clear();
            try {
                object.finalize();
            } catch (Throwable ex) {
                // The RI silently swallows these, but Android has always logged.
                System.logE("Uncaught exception thrown by finalizer", ex);
            } finally {
                // Done finalizing, stop holding the object as live.
                finalizingObject = null;
            }
        }
    }
 
 

FinalizerDaemon中,会循环检查FinalizerRefenceQueue中是否有Reference,如果有,就会取出,调用对象的finalize方法,同时将zombie置为null,使得对象可以被回收。

所以FinalizerRefence很多,只能说明很多对象定义了finalize方法,而且还活在内存中,并不能表示产生了内存泄漏

你可能感兴趣的:(FinalizerReference 笔记)