ART: Dump allocation stacks in reference table dumps
When allocation tracking is enabled and allocation stacks are available,
print the stack traces of the objects in a reference table dumps, to
aid tracking table overflows.
Extend reference_table_test.
Bug: 67044702
Test: m test-art-host
Change-Id: I0118ba095f08dc66739707cd6a184487974b1570
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index e6e588e..a6df27b 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -19,6 +19,8 @@
#include "android-base/stringprintf.h"
#include "base/mutex.h"
+#include "gc/allocation_record.h"
+#include "gc/heap.h"
#include "indirect_reference_table.h"
#include "mirror/array-inl.h"
#include "mirror/array.h"
@@ -206,6 +208,54 @@
}
}
os << StringPrintf(" %5d: ", idx) << ref << " " << className << extras << "\n";
+ if (runtime->GetHeap()->IsAllocTrackingEnabled()) {
+ MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
+
+ gc::AllocRecordObjectMap* records = runtime->GetHeap()->GetAllocationRecords();
+ DCHECK(records != nullptr);
+ // It's annoying that this is a list. But this code should be very uncommon to be executed.
+
+ auto print_stack = [&](ObjPtr<mirror::Object> to_print, const std::string& msg)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(Locks::alloc_tracker_lock_) {
+ for (auto it = records->Begin(), end = records->End(); it != end; ++it) {
+ GcRoot<mirror::Object>& stack_for_object = it->first;
+ gc::AllocRecord& record = it->second;
+ if (stack_for_object.Read() == to_print.Ptr()) {
+ os << " " << msg << "\n";
+ const gc::AllocRecordStackTrace* trace = record.GetStackTrace();
+ size_t depth = trace->GetDepth();
+ if (depth == 0) {
+ os << " (No managed frames)\n";
+ } else {
+ for (size_t i = 0; i < depth; ++i) {
+ const gc::AllocRecordStackTraceElement& frame = trace->GetStackElement(i);
+ os << " ";
+ if (frame.GetMethod() == nullptr) {
+ os << "(missing method data)\n";
+ continue;
+ }
+ os << frame.GetMethod()->PrettyMethod(true)
+ << ":"
+ << frame.ComputeLineNumber()
+ << "\n";
+ }
+ }
+ break;
+ }
+ }
+ };
+ // Print the stack trace of the ref.
+ print_stack(ref, "Allocated at:");
+
+ // If it's a reference, see if we have data about the referent.
+ if (ref->IsReferenceInstance()) {
+ ObjPtr<mirror::Object> referent = ref->AsReference()->GetReferent();
+ if (referent != nullptr) {
+ print_stack(referent, "Referent allocated at:");
+ }
+ }
+ }
}
// Make a copy of the table and sort it, only adding non null and not cleared elements.