reference_table.cc revision e34fa1df67fbe0173b4ea9abddcc3ae3d0537037
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 74struct ObjectComparator { 75 bool operator()(GcRoot<mirror::Object> root1, GcRoot<mirror::Object> root2) const 76 // TODO: enable analysis when analysis can work with the STL. 77 NO_THREAD_SAFETY_ANALYSIS { 78 Locks::mutator_lock_->AssertSharedHeld(Thread::Current()); 79 mirror::Object* obj1 = root1.Read<kWithoutReadBarrier>(); 80 mirror::Object* obj2 = root2.Read<kWithoutReadBarrier>(); 81 DCHECK(obj1 != nullptr); 82 DCHECK(obj2 != nullptr); 83 Runtime* runtime = Runtime::Current(); 84 DCHECK(!runtime->IsClearedJniWeakGlobal(obj1)); 85 DCHECK(!runtime->IsClearedJniWeakGlobal(obj2)); 86 // Sort by class... 87 if (obj1->GetClass() != obj2->GetClass()) { 88 return obj1->GetClass()->IdentityHashCode() < obj2->GetClass()->IdentityHashCode(); 89 } 90 // ...then by size... 91 const size_t size1 = obj1->SizeOf(); 92 const size_t size2 = obj2->SizeOf(); 93 if (size1 != size2) { 94 return size1 < size2; 95 } 96 // ...and finally by identity hash code. 97 return obj1->IdentityHashCode() < obj2->IdentityHashCode(); 98 } 99}; 100 101// Log an object with some additional info. 102// 103// Pass in the number of elements in the array (or 0 if this is not an 104// array object), and the number of additional objects that are identical 105// or equivalent to the original. 106static void DumpSummaryLine(std::ostream& os, mirror::Object* obj, size_t element_count, 107 int identical, int equiv) 108 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 109 if (obj == NULL) { 110 os << " NULL reference (count=" << equiv << ")\n"; 111 return; 112 } 113 if (Runtime::Current()->IsClearedJniWeakGlobal(obj)) { 114 os << " cleared jweak (count=" << equiv << ")\n"; 115 return; 116 } 117 118 std::string className(PrettyTypeOf(obj)); 119 if (obj->IsClass()) { 120 // We're summarizing multiple instances, so using the exemplar 121 // Class' type parameter here would be misleading. 122 className = "java.lang.Class"; 123 } 124 if (element_count != 0) { 125 StringAppendF(&className, " (%zd elements)", element_count); 126 } 127 128 size_t total = identical + equiv + 1; 129 std::string msg(StringPrintf("%5zd of %s", total, className.c_str())); 130 if (identical + equiv != 0) { 131 StringAppendF(&msg, " (%d unique instances)", equiv + 1); 132 } 133 os << " " << msg << "\n"; 134} 135 136size_t ReferenceTable::Size() const { 137 return entries_.size(); 138} 139 140void ReferenceTable::Dump(std::ostream& os) { 141 os << name_ << " reference table dump:\n"; 142 Dump(os, entries_); 143} 144 145void ReferenceTable::Dump(std::ostream& os, Table& entries) { 146 if (entries.empty()) { 147 os << " (empty)\n"; 148 return; 149 } 150 151 // Dump the most recent N entries. 152 const size_t kLast = 10; 153 size_t count = entries.size(); 154 int first = count - kLast; 155 if (first < 0) { 156 first = 0; 157 } 158 os << " Last " << (count - first) << " entries (of " << count << "):\n"; 159 Runtime* runtime = Runtime::Current(); 160 for (int idx = count - 1; idx >= first; --idx) { 161 mirror::Object* ref = entries[idx].Read(); 162 if (ref == nullptr) { 163 continue; 164 } 165 if (runtime->IsClearedJniWeakGlobal(ref)) { 166 os << StringPrintf(" %5d: cleared jweak\n", idx); 167 continue; 168 } 169 if (ref->GetClass() == nullptr) { 170 // should only be possible right after a plain dvmMalloc(). 171 size_t size = ref->SizeOf(); 172 os << StringPrintf(" %5d: %p (raw) (%zd bytes)\n", idx, ref, size); 173 continue; 174 } 175 176 std::string className(PrettyTypeOf(ref)); 177 178 std::string extras; 179 size_t element_count = GetElementCount(ref); 180 if (element_count != 0) { 181 StringAppendF(&extras, " (%zd elements)", element_count); 182 } else if (ref->GetClass()->IsStringClass()) { 183 mirror::String* s = ref->AsString(); 184 std::string utf8(s->ToModifiedUtf8()); 185 if (s->GetLength() <= 16) { 186 StringAppendF(&extras, " \"%s\"", utf8.c_str()); 187 } else { 188 StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength()); 189 } 190 } 191 os << StringPrintf(" %5d: ", idx) << ref << " " << className << extras << "\n"; 192 } 193 194 // Make a copy of the table and sort it, only adding non null and not cleared elements. 195 Table sorted_entries; 196 for (GcRoot<mirror::Object>& root : entries) { 197 if (!root.IsNull() && !runtime->IsClearedJniWeakGlobal(root.Read())) { 198 sorted_entries.push_back(root); 199 } 200 } 201 if (sorted_entries.empty()) { 202 return; 203 } 204 std::sort(sorted_entries.begin(), sorted_entries.end(), ObjectComparator()); 205 206 // Dump a summary of the whole table. 207 os << " Summary:\n"; 208 size_t equiv = 0; 209 size_t identical = 0; 210 mirror::Object* prev = nullptr; 211 for (GcRoot<mirror::Object>& root : sorted_entries) { 212 mirror::Object* current = root.Read<kWithoutReadBarrier>(); 213 if (prev != nullptr) { 214 const size_t element_count = GetElementCount(prev); 215 if (current == prev) { 216 // Same reference, added more than once. 217 ++identical; 218 } else if (current->GetClass() == prev->GetClass() && 219 GetElementCount(current) == element_count) { 220 // Same class / element count, different object. 221 ++equiv; 222 } else { 223 // Different class. 224 DumpSummaryLine(os, prev, element_count, identical, equiv); 225 equiv = 0; 226 identical = 0; 227 } 228 } 229 prev = current; 230 } 231 // Handle the last entry. 232 DumpSummaryLine(os, prev, GetElementCount(prev), identical, equiv); 233} 234 235void ReferenceTable::VisitRoots(RootCallback* visitor, void* arg, const RootInfo& root_info) { 236 for (GcRoot<mirror::Object>& root : entries_) { 237 root.VisitRoot(visitor, arg, root_info); 238 } 239} 240 241} // namespace art 242