Add class flags to class to help GC scanning
Reduces GC time and pauses by reducing the number of loads required
to scan an object.
Average total GC time before on EvaluateAndApplyChanges (EAAC): 7.452s
After: 7.144s
Average GC pause times before on EAAC: 860.67us
After: 722.75us
Adding the class flags field cause a memory increase of ~24k system
wide on low memory devices.
Change-Id: I3f04212d5787bfbf5e55026584d149f55476105e
diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h
index a3cc831..56edcc9 100644
--- a/runtime/gc/collector/mark_sweep-inl.h
+++ b/runtime/gc/collector/mark_sweep-inl.h
@@ -35,10 +35,17 @@
obj->VisitReferences(visitor, ref_visitor);
if (kCountScannedTypes) {
mirror::Class* klass = obj->GetClass<kVerifyNone>();
- if (UNLIKELY(klass == mirror::Class::GetJavaLangClass())) {
+ uint32_t class_flags = klass->GetClassFlags();
+ if ((class_flags & mirror::kClassFlagNoReferenceFields) != 0) {
+ ++no_reference_class_count_;
+ } else if (class_flags == mirror::kClassFlagNormal) {
+ ++normal_count_;
+ } else if (class_flags == mirror::kClassFlagObjectArray) {
+ ++object_array_count_;
+ } else if (class_flags == mirror::kClassFlagClass) {
++class_count_;
- } else if (UNLIKELY(klass->IsArrayClass<kVerifyNone>())) {
- ++array_count_;
+ } else if ((class_flags & mirror::kClassFlagReference) != 0) {
+ ++reference_count_;
} else {
++other_count_;
}
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index b0a8a5b..7ddc7cc 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -70,7 +70,6 @@
static constexpr bool kProfileLargeObjects = false;
static constexpr bool kMeasureOverhead = false;
static constexpr bool kCountTasks = false;
-static constexpr bool kCountJavaLangRefs = false;
static constexpr bool kCountMarkedObjects = false;
// Turn off kCheckLocks when profiling the GC since it slows the GC down by up to 40%.
@@ -114,15 +113,17 @@
mark_stack_ = heap_->GetMarkStack();
DCHECK(mark_stack_ != nullptr);
immune_region_.Reset();
+ no_reference_class_count_.StoreRelaxed(0);
+ normal_count_.StoreRelaxed(0);
class_count_.StoreRelaxed(0);
- array_count_.StoreRelaxed(0);
+ object_array_count_.StoreRelaxed(0);
other_count_.StoreRelaxed(0);
+ reference_count_.StoreRelaxed(0);
large_object_test_.StoreRelaxed(0);
large_object_mark_.StoreRelaxed(0);
overhead_time_ .StoreRelaxed(0);
work_chunks_created_.StoreRelaxed(0);
work_chunks_deleted_.StoreRelaxed(0);
- reference_count_.StoreRelaxed(0);
mark_null_count_.StoreRelaxed(0);
mark_immune_count_.StoreRelaxed(0);
mark_fastpath_count_.StoreRelaxed(0);
@@ -1265,9 +1266,6 @@
// Process the "referent" field in a java.lang.ref.Reference. If the referent has not yet been
// marked, put it on the appropriate list in the heap for later processing.
void MarkSweep::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref) {
- if (kCountJavaLangRefs) {
- ++reference_count_;
- }
heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, ref, this);
}
@@ -1386,8 +1384,14 @@
void MarkSweep::FinishPhase() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
if (kCountScannedTypes) {
- VLOG(gc) << "MarkSweep scanned classes=" << class_count_.LoadRelaxed()
- << " arrays=" << array_count_.LoadRelaxed() << " other=" << other_count_.LoadRelaxed();
+ VLOG(gc)
+ << "MarkSweep scanned"
+ << " no reference objects=" << no_reference_class_count_.LoadRelaxed()
+ << " normal objects=" << normal_count_.LoadRelaxed()
+ << " classes=" << class_count_.LoadRelaxed()
+ << " object arrays=" << object_array_count_.LoadRelaxed()
+ << " references=" << reference_count_.LoadRelaxed()
+ << " other=" << other_count_.LoadRelaxed();
}
if (kCountTasks) {
VLOG(gc) << "Total number of work chunks allocated: " << work_chunks_created_.LoadRelaxed();
@@ -1399,9 +1403,6 @@
VLOG(gc) << "Large objects tested " << large_object_test_.LoadRelaxed()
<< " marked " << large_object_mark_.LoadRelaxed();
}
- if (kCountJavaLangRefs) {
- VLOG(gc) << "References scanned " << reference_count_.LoadRelaxed();
- }
if (kCountMarkedObjects) {
VLOG(gc) << "Marked: null=" << mark_null_count_.LoadRelaxed()
<< " immune=" << mark_immune_count_.LoadRelaxed()
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 8bd1dc7..371bba5 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -245,7 +245,7 @@
void RevokeAllThreadLocalBuffers();
// Whether or not we count how many of each type of object were scanned.
- static const bool kCountScannedTypes = false;
+ static constexpr bool kCountScannedTypes = false;
// Current space, we check this space first to avoid searching for the appropriate space for an
// object.
@@ -260,18 +260,23 @@
// Parallel finger.
AtomicInteger atomic_finger_;
+
+ AtomicInteger no_reference_class_count_;
+ AtomicInteger normal_count_;
// Number of classes scanned, if kCountScannedTypes.
AtomicInteger class_count_;
- // Number of arrays scanned, if kCountScannedTypes.
- AtomicInteger array_count_;
+ // Number of object arrays scanned, if kCountScannedTypes.
+ AtomicInteger object_array_count_;
// Number of non-class/arrays scanned, if kCountScannedTypes.
AtomicInteger other_count_;
+ // Number of java.lang.ref.Reference instances.
+ AtomicInteger reference_count_;
+
AtomicInteger large_object_test_;
AtomicInteger large_object_mark_;
AtomicInteger overhead_time_;
AtomicInteger work_chunks_created_;
AtomicInteger work_chunks_deleted_;
- AtomicInteger reference_count_;
AtomicInteger mark_null_count_;
AtomicInteger mark_immune_count_;
AtomicInteger mark_fastpath_count_;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d7f918b..b8c4478 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -3707,7 +3707,7 @@
void Heap::CheckPreconditionsForAllocObject(mirror::Class* c, size_t byte_count) {
CHECK(c == nullptr || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) ||
- (c->IsVariableSize() || c->GetObjectSize() == byte_count));
+ (c->IsVariableSize() || c->GetObjectSize() == byte_count)) << c->GetClassFlags();
CHECK_GE(byte_count, sizeof(mirror::Object));
}