summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/runtime.cc32
1 files changed, 28 insertions, 4 deletions
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index ccbd929acc..eaeda04256 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -3299,11 +3299,28 @@ void Runtime::ResetStartupCompleted() {
startup_completed_.store(false, std::memory_order_seq_cst);
}
-class UnlinkStartupDexCacheVisitor : public DexCacheVisitor {
+class CollectStartupDexCacheVisitor : public DexCacheVisitor {
public:
+ explicit CollectStartupDexCacheVisitor(VariableSizedHandleScope& handles) : handles_(handles) {}
+
void Visit(ObjPtr<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::dex_lock_, Locks::mutator_lock_) override {
- dex_cache->UnlinkStartupCaches();
+ handles_.NewHandle(dex_cache);
+ }
+
+ private:
+ VariableSizedHandleScope& handles_;
+};
+
+class UnlinkVisitor {
+ public:
+ UnlinkVisitor() {}
+
+ void VisitRootIfNonNull(StackReference<mirror::Object>* ref)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!ref->IsNull()) {
+ ref->AsMirrorPtr()->AsDexCache()->UnlinkStartupCaches();
+ }
}
};
@@ -3321,9 +3338,10 @@ class Runtime::NotifyStartupCompletedTask : public gc::HeapTask {
ScopedTrace trace("Releasing dex caches and app image spaces metadata");
ScopedObjectAccess soa(Thread::Current());
+ // Collect dex caches that were allocated with the startup linear alloc.
+ VariableSizedHandleScope handles(soa.Self());
{
- // Unlink dex caches that were allocated with the startup linear alloc.
- UnlinkStartupDexCacheVisitor visitor;
+ CollectStartupDexCacheVisitor visitor(handles);
ReaderMutexLock mu(self, *Locks::dex_lock_);
runtime->GetClassLinker()->VisitDexCaches(&visitor);
}
@@ -3341,6 +3359,12 @@ class Runtime::NotifyStartupCompletedTask : public gc::HeapTask {
gc::ScopedInterruptibleGCCriticalSection sigcs(self,
gc::kGcCauseRunEmptyCheckpoint,
gc::kCollectorTypeCriticalSection);
+ // Do the unlinking of dex cache arrays in the GC critical section to
+ // avoid GC not seeing these arrays. We do it before the checkpoint so
+ // we know after the checkpoint, no thread is holding onto the array.
+ UnlinkVisitor visitor;
+ handles.VisitRoots(visitor);
+
runtime->GetThreadList()->RunEmptyCheckpoint();
}