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 31 namespace art { 32 33 ReferenceTable::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 39 ReferenceTable::~ReferenceTable() { 40 } 41 42 void ReferenceTable::Add(mirror::Object* obj) { 43 DCHECK(obj != nullptr); 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 52 void 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. 65 static size_t GetElementCount(mirror::Object* obj) SHARED_REQUIRES(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. 79 static void DumpSummaryLine(std::ostream& os, mirror::Object* obj, size_t element_count, 80 int identical, int equiv) 81 SHARED_REQUIRES(Locks::mutator_lock_) { 82 if (obj == nullptr) { 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 109 size_t ReferenceTable::Size() const { 110 return entries_.size(); 111 } 112 113 void ReferenceTable::Dump(std::ostream& os) { 114 os << name_ << " reference table dump:\n"; 115 Dump(os, entries_); 116 } 117 118 void 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 } else if (ref->IsReferenceInstance()) { 196 mirror::Object* referent = ref->AsReference()->GetReferent(); 197 if (referent == nullptr) { 198 extras = " (storing null)"; 199 } else { 200 extras = StringPrintf(" (storing a %s)", PrettyTypeOf(referent).c_str()); 201 } 202 } 203 os << StringPrintf(" %5d: ", idx) << ref << " " << className << extras << "\n"; 204 } 205 206 // Make a copy of the table and sort it, only adding non null and not cleared elements. 207 Table sorted_entries; 208 for (GcRoot<mirror::Object>& root : entries) { 209 if (!root.IsNull() && !runtime->IsClearedJniWeakGlobal(root.Read())) { 210 sorted_entries.push_back(root); 211 } 212 } 213 if (sorted_entries.empty()) { 214 return; 215 } 216 std::sort(sorted_entries.begin(), sorted_entries.end(), GcRootComparator()); 217 218 // Dump a summary of the whole table. 219 os << " Summary:\n"; 220 size_t equiv = 0; 221 size_t identical = 0; 222 mirror::Object* prev = nullptr; 223 for (GcRoot<mirror::Object>& root : sorted_entries) { 224 mirror::Object* current = root.Read<kWithoutReadBarrier>(); 225 if (prev != nullptr) { 226 const size_t element_count = GetElementCount(prev); 227 if (current == prev) { 228 // Same reference, added more than once. 229 ++identical; 230 } else if (current->GetClass() == prev->GetClass() && 231 GetElementCount(current) == element_count) { 232 // Same class / element count, different object. 233 ++equiv; 234 } else { 235 // Different class. 236 DumpSummaryLine(os, prev, element_count, identical, equiv); 237 equiv = 0; 238 identical = 0; 239 } 240 } 241 prev = current; 242 } 243 // Handle the last entry. 244 DumpSummaryLine(os, prev, GetElementCount(prev), identical, equiv); 245 } 246 247 void ReferenceTable::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) { 248 BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(visitor, root_info); 249 for (GcRoot<mirror::Object>& root : entries_) { 250 buffered_visitor.VisitRoot(root); 251 } 252 } 253 254 } // namespace art 255