Reduced frequency of blocks for concurrent gc
Immediately return for references that are marked before reference
processing without blocking. Soft references are kept in the queue until
the reference processor stops preserving, after which, all marked
references are removed. Finalizer references will still block on get().
Bug: 15471830
Change-Id: I588fcaef40b79ed7c95a4aa7f4fc2e17ee0c288f
diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc
index caacef5..3910c29 100644
--- a/runtime/gc/reference_queue.cc
+++ b/runtime/gc/reference_queue.cc
@@ -160,22 +160,23 @@
}
}
-void ReferenceQueue::PreserveSomeSoftReferences(IsMarkedCallback* preserve_callback, void* arg) {
- ReferenceQueue cleared;
- while (!IsEmpty()) {
- mirror::Reference* ref = DequeuePendingReference();
+void ReferenceQueue::ForwardSoftReferences(IsMarkedCallback* preserve_callback,
+ void* arg) {
+ if (UNLIKELY(IsEmpty())) {
+ return;
+ }
+ mirror::Reference* const head = list_;
+ mirror::Reference* ref = head;
+ do {
mirror::Object* referent = ref->GetReferent<kWithoutReadBarrier>();
if (referent != nullptr) {
mirror::Object* forward_address = preserve_callback(referent, arg);
- if (forward_address == nullptr) {
- // Either the reference isn't marked or we don't wish to preserve it.
- cleared.EnqueuePendingReference(ref);
- } else if (forward_address != referent) {
+ if (forward_address != nullptr && forward_address != referent) {
ref->SetReferent<false>(forward_address);
}
}
- }
- list_ = cleared.GetList();
+ ref = ref->GetPendingNext();
+ } while (LIKELY(ref != head));
}
} // namespace gc