blob: d8b9dcc016d9361bbe9bf47444ae0ee095292602 [file] [log] [blame]
Elliott Hughes11e45072011-08-16 17:40:46 -07001/*
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
Andreas Gampe46ee31b2016-12-14 10:11:49 -080019#include "android-base/stringprintf.h"
20
Elliott Hughes76b61672012-12-12 17:47:30 -080021#include "base/mutex.h"
Elliott Hughes6c1a3942011-08-17 15:00:06 -070022#include "indirect_reference_table.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080023#include "mirror/array.h"
24#include "mirror/array-inl.h"
25#include "mirror/class.h"
26#include "mirror/class-inl.h"
27#include "mirror/object-inl.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070028#include "mirror/string-inl.h"
Ian Rogersc0542af2014-09-03 16:16:56 -070029#include "runtime-inl.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080030#include "thread.h"
31#include "utils.h"
Elliott Hughes11e45072011-08-16 17:40:46 -070032
33namespace art {
34
Andreas Gampe46ee31b2016-12-14 10:11:49 -080035using android::base::StringAppendF;
36using android::base::StringPrintf;
37
Elliott Hughesbb1e8f02011-10-18 14:14:25 -070038ReferenceTable::ReferenceTable(const char* name, size_t initial_size, size_t max_size)
39 : name_(name), max_size_(max_size) {
Elliott Hughes11e45072011-08-16 17:40:46 -070040 CHECK_LE(initial_size, max_size);
41 entries_.reserve(initial_size);
42}
43
Elliott Hughesc1674ed2011-08-25 18:09:09 -070044ReferenceTable::~ReferenceTable() {
45}
46
Mathieu Chartierc4f39252016-10-05 18:32:08 -070047void ReferenceTable::Add(ObjPtr<mirror::Object> obj) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -070048 DCHECK(obj != nullptr);
Mathieu Chartier9d156d52016-10-06 17:44:26 -070049 VerifyObject(obj);
Mathieu Chartier423d2a32013-09-12 17:33:56 -070050 if (entries_.size() >= max_size_) {
Elliott Hughes11e45072011-08-16 17:40:46 -070051 LOG(FATAL) << "ReferenceTable '" << name_ << "' "
52 << "overflowed (" << max_size_ << " entries)";
53 }
Hiroshi Yamauchi94f7b492014-07-22 18:08:23 -070054 entries_.push_back(GcRoot<mirror::Object>(obj));
Elliott Hughes11e45072011-08-16 17:40:46 -070055}
56
Mathieu Chartierc4f39252016-10-05 18:32:08 -070057void ReferenceTable::Remove(ObjPtr<mirror::Object> obj) {
Elliott Hughes11e45072011-08-16 17:40:46 -070058 // We iterate backwards on the assumption that references are LIFO.
59 for (int i = entries_.size() - 1; i >= 0; --i) {
Mathieu Chartierc4f39252016-10-05 18:32:08 -070060 ObjPtr<mirror::Object> entry = entries_[i].Read();
Hiroshi Yamauchiea2e1bd2014-06-18 13:47:35 -070061 if (entry == obj) {
Elliott Hughes11e45072011-08-16 17:40:46 -070062 entries_.erase(entries_.begin() + i);
63 return;
64 }
65 }
66}
67
Carl Shapiro5b1982d2011-08-16 18:35:19 -070068// If "obj" is an array, return the number of elements in the array.
69// Otherwise, return zero.
Mathieu Chartierc4f39252016-10-05 18:32:08 -070070static size_t GetElementCount(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_) {
Ian Rogersc0542af2014-09-03 16:16:56 -070071 // We assume the special cleared value isn't an array in the if statement below.
72 DCHECK(!Runtime::Current()->GetClearedJniWeakGlobal()->IsArrayInstance());
73 if (obj == nullptr || !obj->IsArrayInstance()) {
Elliott Hughes11e45072011-08-16 17:40:46 -070074 return 0;
75 }
76 return obj->AsArray()->GetLength();
77}
78
Carl Shapiro5b1982d2011-08-16 18:35:19 -070079// Log an object with some additional info.
80//
81// Pass in the number of elements in the array (or 0 if this is not an
82// array object), and the number of additional objects that are identical
83// or equivalent to the original.
Mathieu Chartierc4f39252016-10-05 18:32:08 -070084static void DumpSummaryLine(std::ostream& os, ObjPtr<mirror::Object> obj, size_t element_count,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070085 int identical, int equiv)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070086 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -070087 if (obj == nullptr) {
88 os << " null reference (count=" << equiv << ")\n";
Elliott Hughes11e45072011-08-16 17:40:46 -070089 return;
90 }
Ian Rogersc0542af2014-09-03 16:16:56 -070091 if (Runtime::Current()->IsClearedJniWeakGlobal(obj)) {
Elliott Hughes73e66f72012-05-09 09:34:45 -070092 os << " cleared jweak (count=" << equiv << ")\n";
Elliott Hughes11e45072011-08-16 17:40:46 -070093 return;
94 }
95
David Sehr709b0702016-10-13 09:12:37 -070096 std::string className(obj->PrettyTypeOf());
Elliott Hughes11e45072011-08-16 17:40:46 -070097 if (obj->IsClass()) {
98 // We're summarizing multiple instances, so using the exemplar
99 // Class' type parameter here would be misleading.
100 className = "java.lang.Class";
101 }
Elliott Hughes73e66f72012-05-09 09:34:45 -0700102 if (element_count != 0) {
103 StringAppendF(&className, " (%zd elements)", element_count);
Elliott Hughes11e45072011-08-16 17:40:46 -0700104 }
105
106 size_t total = identical + equiv + 1;
Elliott Hughes215f3142012-01-19 00:22:47 -0800107 std::string msg(StringPrintf("%5zd of %s", total, className.c_str()));
Elliott Hughes11e45072011-08-16 17:40:46 -0700108 if (identical + equiv != 0) {
109 StringAppendF(&msg, " (%d unique instances)", equiv + 1);
110 }
Elliott Hughes73e66f72012-05-09 09:34:45 -0700111 os << " " << msg << "\n";
Elliott Hughes11e45072011-08-16 17:40:46 -0700112}
113
114size_t ReferenceTable::Size() const {
115 return entries_.size();
116}
117
Hiroshi Yamauchiea2e1bd2014-06-18 13:47:35 -0700118void ReferenceTable::Dump(std::ostream& os) {
Elliott Hughes73e66f72012-05-09 09:34:45 -0700119 os << name_ << " reference table dump:\n";
120 Dump(os, entries_);
Elliott Hughes6c1a3942011-08-17 15:00:06 -0700121}
Elliott Hughes11e45072011-08-16 17:40:46 -0700122
Hiroshi Yamauchiea2e1bd2014-06-18 13:47:35 -0700123void ReferenceTable::Dump(std::ostream& os, Table& entries) {
Mathieu Chartier4c4d6092015-01-22 17:02:27 -0800124 // Compare GC roots, first by class, then size, then address.
125 struct GcRootComparator {
126 bool operator()(GcRoot<mirror::Object> root1, GcRoot<mirror::Object> root2) const
127 // TODO: enable analysis when analysis can work with the STL.
128 NO_THREAD_SAFETY_ANALYSIS {
129 Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
130 // These GC roots are already forwarded in ReferenceTable::Dump. We sort by class since there
131 // are no suspend points which can happen during the sorting process. This works since
132 // we are guaranteed that the addresses of obj1, obj2, obj1->GetClass, obj2->GetClass wont
133 // change during the sorting process. The classes are forwarded by ref->GetClass().
Mathieu Chartierc4f39252016-10-05 18:32:08 -0700134 ObjPtr<mirror::Object> obj1 = root1.Read<kWithoutReadBarrier>();
135 ObjPtr<mirror::Object> obj2 = root2.Read<kWithoutReadBarrier>();
Mathieu Chartier4c4d6092015-01-22 17:02:27 -0800136 DCHECK(obj1 != nullptr);
137 DCHECK(obj2 != nullptr);
138 Runtime* runtime = Runtime::Current();
139 DCHECK(!runtime->IsClearedJniWeakGlobal(obj1));
140 DCHECK(!runtime->IsClearedJniWeakGlobal(obj2));
141 // Sort by class...
142 if (obj1->GetClass() != obj2->GetClass()) {
143 return obj1->GetClass() < obj2->GetClass();
144 }
145 // ...then by size...
146 const size_t size1 = obj1->SizeOf();
147 const size_t size2 = obj2->SizeOf();
148 if (size1 != size2) {
149 return size1 < size2;
150 }
151 // ...and finally by address.
Mathieu Chartierc4f39252016-10-05 18:32:08 -0700152 return obj1.Ptr() < obj2.Ptr();
Mathieu Chartier4c4d6092015-01-22 17:02:27 -0800153 }
154 };
155
Elliott Hughes6c1a3942011-08-17 15:00:06 -0700156 if (entries.empty()) {
Elliott Hughes73e66f72012-05-09 09:34:45 -0700157 os << " (empty)\n";
Elliott Hughes11e45072011-08-16 17:40:46 -0700158 return;
159 }
160
161 // Dump the most recent N entries.
162 const size_t kLast = 10;
Elliott Hughes6c1a3942011-08-17 15:00:06 -0700163 size_t count = entries.size();
Elliott Hughes11e45072011-08-16 17:40:46 -0700164 int first = count - kLast;
165 if (first < 0) {
166 first = 0;
167 }
Elliott Hughes73e66f72012-05-09 09:34:45 -0700168 os << " Last " << (count - first) << " entries (of " << count << "):\n";
Mathieu Chartier38ebea42014-12-08 11:50:36 -0800169 Runtime* runtime = Runtime::Current();
Elliott Hughes11e45072011-08-16 17:40:46 -0700170 for (int idx = count - 1; idx >= first; --idx) {
Mathieu Chartierc4f39252016-10-05 18:32:08 -0700171 ObjPtr<mirror::Object> ref = entries[idx].Read();
Mathieu Chartier38ebea42014-12-08 11:50:36 -0800172 if (ref == nullptr) {
Elliott Hughes11e45072011-08-16 17:40:46 -0700173 continue;
174 }
Mathieu Chartier38ebea42014-12-08 11:50:36 -0800175 if (runtime->IsClearedJniWeakGlobal(ref)) {
Elliott Hughes73e66f72012-05-09 09:34:45 -0700176 os << StringPrintf(" %5d: cleared jweak\n", idx);
Elliott Hughes11e45072011-08-16 17:40:46 -0700177 continue;
178 }
Mathieu Chartier38ebea42014-12-08 11:50:36 -0800179 if (ref->GetClass() == nullptr) {
Elliott Hughes11e45072011-08-16 17:40:46 -0700180 // should only be possible right after a plain dvmMalloc().
181 size_t size = ref->SizeOf();
Mathieu Chartierc4f39252016-10-05 18:32:08 -0700182 os << StringPrintf(" %5d: %p (raw) (%zd bytes)\n", idx, ref.Ptr(), size);
Elliott Hughes11e45072011-08-16 17:40:46 -0700183 continue;
184 }
185
David Sehr709b0702016-10-13 09:12:37 -0700186 std::string className(ref->PrettyTypeOf());
Elliott Hughes11e45072011-08-16 17:40:46 -0700187
188 std::string extras;
Elliott Hughes73e66f72012-05-09 09:34:45 -0700189 size_t element_count = GetElementCount(ref);
190 if (element_count != 0) {
191 StringAppendF(&extras, " (%zd elements)", element_count);
192 } else if (ref->GetClass()->IsStringClass()) {
Mathieu Chartierc4f39252016-10-05 18:32:08 -0700193 ObjPtr<mirror::String> s = ref->AsString();
Elliott Hughes73e66f72012-05-09 09:34:45 -0700194 std::string utf8(s->ToModifiedUtf8());
195 if (s->GetLength() <= 16) {
196 StringAppendF(&extras, " \"%s\"", utf8.c_str());
Elliott Hughes11e45072011-08-16 17:40:46 -0700197 } else {
Elliott Hughes73e66f72012-05-09 09:34:45 -0700198 StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength());
Elliott Hughes11e45072011-08-16 17:40:46 -0700199 }
Andreas Gampea3bbf8b2016-09-27 18:45:02 -0700200 } else if (ref->IsReferenceInstance()) {
Mathieu Chartierc4f39252016-10-05 18:32:08 -0700201 ObjPtr<mirror::Object> referent = ref->AsReference()->GetReferent();
Andreas Gampea3bbf8b2016-09-27 18:45:02 -0700202 if (referent == nullptr) {
203 extras = " (referent is null)";
204 } else {
David Sehr709b0702016-10-13 09:12:37 -0700205 extras = StringPrintf(" (referent is a %s)", referent->PrettyTypeOf().c_str());
Andreas Gampea3bbf8b2016-09-27 18:45:02 -0700206 }
Elliott Hughes11e45072011-08-16 17:40:46 -0700207 }
Elliott Hughes73e66f72012-05-09 09:34:45 -0700208 os << StringPrintf(" %5d: ", idx) << ref << " " << className << extras << "\n";
Elliott Hughes11e45072011-08-16 17:40:46 -0700209 }
210
Mathieu Chartier38ebea42014-12-08 11:50:36 -0800211 // Make a copy of the table and sort it, only adding non null and not cleared elements.
Hiroshi Yamauchiea2e1bd2014-06-18 13:47:35 -0700212 Table sorted_entries;
Mathieu Chartier38ebea42014-12-08 11:50:36 -0800213 for (GcRoot<mirror::Object>& root : entries) {
Mathieu Chartier4099b782014-12-08 12:59:27 -0800214 if (!root.IsNull() && !runtime->IsClearedJniWeakGlobal(root.Read())) {
Mathieu Chartier38ebea42014-12-08 11:50:36 -0800215 sorted_entries.push_back(root);
216 }
Elliott Hughes11e45072011-08-16 17:40:46 -0700217 }
218 if (sorted_entries.empty()) {
219 return;
220 }
Mathieu Chartier4c4d6092015-01-22 17:02:27 -0800221 std::sort(sorted_entries.begin(), sorted_entries.end(), GcRootComparator());
Elliott Hughes11e45072011-08-16 17:40:46 -0700222
Andreas Gampe6e970e72016-11-14 17:00:28 -0800223 class SummaryElement {
224 public:
225 GcRoot<mirror::Object> root;
226 size_t equiv;
227 size_t identical;
228
229 SummaryElement() : equiv(0), identical(0) {}
230 SummaryElement(SummaryElement&& ref) {
231 root = ref.root;
232 equiv = ref.equiv;
233 identical = ref.identical;
234 }
235 SummaryElement(const SummaryElement&) = default;
236 SummaryElement& operator=(SummaryElement&&) = default;
237
238 void Reset(GcRoot<mirror::Object>& _root) {
239 root = _root;
240 equiv = 0;
241 identical = 0;
242 }
243 };
244 std::vector<SummaryElement> sorted_summaries;
245 {
246 SummaryElement prev;
247
248 for (GcRoot<mirror::Object>& root : sorted_entries) {
249 ObjPtr<mirror::Object> current = root.Read<kWithoutReadBarrier>();
250
251 if (UNLIKELY(prev.root.IsNull())) {
252 prev.Reset(root);
253 continue;
254 }
255
256 ObjPtr<mirror::Object> prevObj = prev.root.Read<kWithoutReadBarrier>();
257 if (current == prevObj) {
258 // Same reference, added more than once.
259 ++prev.identical;
260 } else if (current->GetClass() == prevObj->GetClass() &&
261 GetElementCount(current) == GetElementCount(prevObj)) {
262 // Same class / element count, different object.
263 ++prev.equiv;
264 } else {
265 sorted_summaries.push_back(prev);
266 prev.Reset(root);
267 }
268 prev.root = root;
269 }
270 sorted_summaries.push_back(prev);
271
272 // Compare summary elements, first by combined count, then by identical (indicating leaks),
273 // then by class (and size and address).
274 struct SummaryElementComparator {
275 GcRootComparator gc_root_cmp;
276
277 bool operator()(SummaryElement& elem1, SummaryElement& elem2) const
278 NO_THREAD_SAFETY_ANALYSIS {
279 Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
280
281 size_t count1 = elem1.equiv + elem1.identical;
282 size_t count2 = elem2.equiv + elem2.identical;
283 if (count1 != count2) {
284 return count1 > count2;
285 }
286
287 if (elem1.identical != elem2.identical) {
288 return elem1.identical > elem2.identical;
289 }
290
291 // Otherwise, compare the GC roots as before.
292 return gc_root_cmp(elem1.root, elem2.root);
293 }
294 };
295 std::sort(sorted_summaries.begin(), sorted_summaries.end(), SummaryElementComparator());
296 }
297
Elliott Hughes11e45072011-08-16 17:40:46 -0700298 // Dump a summary of the whole table.
Elliott Hughes73e66f72012-05-09 09:34:45 -0700299 os << " Summary:\n";
Andreas Gampe6e970e72016-11-14 17:00:28 -0800300 for (SummaryElement& elem : sorted_summaries) {
301 ObjPtr<mirror::Object> elemObj = elem.root.Read<kWithoutReadBarrier>();
302 DumpSummaryLine(os, elemObj, GetElementCount(elemObj), elem.identical, elem.equiv);
Elliott Hughes11e45072011-08-16 17:40:46 -0700303 }
Elliott Hughes11e45072011-08-16 17:40:46 -0700304}
305
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700306void ReferenceTable::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
Mathieu Chartier4809d0a2015-04-07 10:39:04 -0700307 BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(visitor, root_info);
Hiroshi Yamauchi94f7b492014-07-22 18:08:23 -0700308 for (GcRoot<mirror::Object>& root : entries_) {
Mathieu Chartierbb87e0f2015-04-03 11:21:55 -0700309 buffered_visitor.VisitRoot(root);
Elliott Hughes410c0c82011-09-01 17:58:25 -0700310 }
311}
312
Elliott Hughes11e45072011-08-16 17:40:46 -0700313} // namespace art