reference_table.cc revision 4c4d609a3f1d67c76c855df13c2c1be9c315a6c9
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "reference_table.h" 18 19#include "base/mutex.h" 20#include "indirect_reference_table.h" 21#include "mirror/array.h" 22#include "mirror/array-inl.h" 23#include "mirror/class.h" 24#include "mirror/class-inl.h" 25#include "mirror/object-inl.h" 26#include "mirror/string-inl.h" 27#include "runtime-inl.h" 28#include "thread.h" 29#include "utils.h" 30 31namespace art { 32 33ReferenceTable::ReferenceTable(const char* name, size_t initial_size, size_t max_size) 34 : name_(name), max_size_(max_size) { 35 CHECK_LE(initial_size, max_size); 36 entries_.reserve(initial_size); 37} 38 39ReferenceTable::~ReferenceTable() { 40} 41 42void ReferenceTable::Add(mirror::Object* obj) { 43 DCHECK(obj != NULL); 44 VerifyObject(obj); 45 if (entries_.size() >= max_size_) { 46 LOG(FATAL) << "ReferenceTable '" << name_ << "' " 47 << "overflowed (" << max_size_ << " entries)"; 48 } 49 entries_.push_back(GcRoot<mirror::Object>(obj)); 50} 51 52void ReferenceTable::Remove(mirror::Object* obj) { 53 // We iterate backwards on the assumption that references are LIFO. 54 for (int i = entries_.size() - 1; i >= 0; --i) { 55 mirror::Object* entry = entries_[i].Read(); 56 if (entry == obj) { 57 entries_.erase(entries_.begin() + i); 58 return; 59 } 60 } 61} 62 63// If "obj" is an array, return the number of elements in the array. 64// Otherwise, return zero. 65static size_t GetElementCount(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 66 // We assume the special cleared value isn't an array in the if statement below. 67 DCHECK(!Runtime::Current()->GetClearedJniWeakGlobal()->IsArrayInstance()); 68 if (obj == nullptr || !obj->IsArrayInstance()) { 69 return 0; 70 } 71 return obj->AsArray()->GetLength(); 72} 73 74// Log an object with some additional info. 75// 76// Pass in the number of elements in the array (or 0 if this is not an 77// array object), and the number of additional objects that are identical 78// or equivalent to the original. 79static void DumpSummaryLine(std::ostream& os, mirror::Object* obj, size_t element_count, 80 int identical, int equiv) 81 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 82 if (obj == NULL) { 83 os << " NULL reference (count=" << equiv << ")\n"; 84 return; 85 } 86 if (Runtime::Current()->IsClearedJniWeakGlobal(obj)) { 87 os << " cleared jweak (count=" << equiv << ")\n"; 88 return; 89 } 90 91 std::string className(PrettyTypeOf(obj)); 92 if (obj->IsClass()) { 93 // We're summarizing multiple instances, so using the exemplar 94 // Class' type parameter here would be misleading. 95 className = "java.lang.Class"; 96 } 97 if (element_count != 0) { 98 StringAppendF(&className, " (%zd elements)", element_count); 99 } 100 101 size_t total = identical + equiv + 1; 102 std::string msg(StringPrintf("%5zd of %s", total, className.c_str())); 103 if (identical + equiv != 0) { 104 StringAppendF(&msg, " (%d unique instances)", equiv + 1); 105 } 106 os << " " << msg << "\n"; 107} 108 109size_t ReferenceTable::Size() const { 110 return entries_.size(); 111} 112 113void ReferenceTable::Dump(std::ostream& os) { 114 os << name_ << " reference table dump:\n"; 115 Dump(os, entries_); 116} 117 118void ReferenceTable::Dump(std::ostream& os, Table& entries) { 119 // Compare GC roots, first by class, then size, then address. 120 struct GcRootComparator { 121 bool operator()(GcRoot<mirror::Object> root1, GcRoot<mirror::Object> root2) const 122 // TODO: enable analysis when analysis can work with the STL. 123 NO_THREAD_SAFETY_ANALYSIS { 124 Locks::mutator_lock_->AssertSharedHeld(Thread::Current()); 125 // These GC roots are already forwarded in ReferenceTable::Dump. We sort by class since there 126 // are no suspend points which can happen during the sorting process. This works since 127 // we are guaranteed that the addresses of obj1, obj2, obj1->GetClass, obj2->GetClass wont 128 // change during the sorting process. The classes are forwarded by ref->GetClass(). 129 mirror::Object* obj1 = root1.Read<kWithoutReadBarrier>(); 130 mirror::Object* obj2 = root2.Read<kWithoutReadBarrier>(); 131 DCHECK(obj1 != nullptr); 132 DCHECK(obj2 != nullptr); 133 Runtime* runtime = Runtime::Current(); 134 DCHECK(!runtime->IsClearedJniWeakGlobal(obj1)); 135 DCHECK(!runtime->IsClearedJniWeakGlobal(obj2)); 136 // Sort by class... 137 if (obj1->GetClass() != obj2->GetClass()) { 138 return obj1->GetClass() < obj2->GetClass(); 139 } 140 // ...then by size... 141 const size_t size1 = obj1->SizeOf(); 142 const size_t size2 = obj2->SizeOf(); 143 if (size1 != size2) { 144 return size1 < size2; 145 } 146 // ...and finally by address. 147 return obj1 < obj2; 148 } 149 }; 150 151 if (entries.empty()) { 152 os << " (empty)\n"; 153 return; 154 } 155 156 // Dump the most recent N entries. 157 const size_t kLast = 10; 158 size_t count = entries.size(); 159 int first = count - kLast; 160 if (first < 0) { 161 first = 0; 162 } 163 os << " Last " << (count - first) << " entries (of " << count << "):\n"; 164 Runtime* runtime = Runtime::Current(); 165 for (int idx = count - 1; idx >= first; --idx) { 166 mirror::Object* ref = entries[idx].Read(); 167 if (ref == nullptr) { 168 continue; 169 } 170 if (runtime->IsClearedJniWeakGlobal(ref)) { 171 os << StringPrintf(" %5d: cleared jweak\n", idx); 172 continue; 173 } 174 if (ref->GetClass() == nullptr) { 175 // should only be possible right after a plain dvmMalloc(). 176 size_t size = ref->SizeOf(); 177 os << StringPrintf(" %5d: %p (raw) (%zd bytes)\n", idx, ref, size); 178 continue; 179 } 180 181 std::string className(PrettyTypeOf(ref)); 182 183 std::string extras; 184 size_t element_count = GetElementCount(ref); 185 if (element_count != 0) { 186 StringAppendF(&extras, " (%zd elements)", element_count); 187 } else if (ref->GetClass()->IsStringClass()) { 188 mirror::String* s = ref->AsString(); 189 std::string utf8(s->ToModifiedUtf8()); 190 if (s->GetLength() <= 16) { 191 StringAppendF(&extras, " \"%s\"", utf8.c_str()); 192 } else { 193 StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength()); 194 } 195 } 196 os << StringPrintf(" %5d: ", idx) << ref << " " << className << extras << "\n"; 197 } 198 199 // Make a copy of the table and sort it, only adding non null and not cleared elements. 200 Table sorted_entries; 201 for (GcRoot<mirror::Object>& root : entries) { 202 if (!root.IsNull() && !runtime->IsClearedJniWeakGlobal(root.Read())) { 203 sorted_entries.push_back(root); 204 } 205 } 206 if (sorted_entries.empty()) { 207 return; 208 } 209 std::sort(sorted_entries.begin(), sorted_entries.end(), GcRootComparator()); 210 211 // Dump a summary of the whole table. 212 os << " Summary:\n"; 213 size_t equiv = 0; 214 size_t identical = 0; 215 mirror::Object* prev = nullptr; 216 for (GcRoot<mirror::Object>& root : sorted_entries) { 217 mirror::Object* current = root.Read<kWithoutReadBarrier>(); 218 if (prev != nullptr) { 219 const size_t element_count = GetElementCount(prev); 220 if (current == prev) { 221 // Same reference, added more than once. 222 ++identical; 223 } else if (current->GetClass() == prev->GetClass() && 224 GetElementCount(current) == element_count) { 225 // Same class / element count, different object. 226 ++equiv; 227 } else { 228 // Different class. 229 DumpSummaryLine(os, prev, element_count, identical, equiv); 230 equiv = 0; 231 identical = 0; 232 } 233 } 234 prev = current; 235 } 236 // Handle the last entry. 237 DumpSummaryLine(os, prev, GetElementCount(prev), identical, equiv); 238} 239 240void ReferenceTable::VisitRoots(RootCallback* visitor, void* arg, const RootInfo& root_info) { 241 for (GcRoot<mirror::Object>& root : entries_) { 242 root.VisitRoot(visitor, arg, root_info); 243 } 244} 245 246} // namespace art 247