blob: 80e3394f86c33a03c57c65899a7a9698ceaa7e91 [file] [log] [blame]
Man Cao8c2ff642015-05-27 17:25:30 -07001/*
2 * Copyright (C) 2015 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 "allocation_record.h"
18
19#include "art_method-inl.h"
Andreas Gampe542451c2016-07-26 09:02:02 -070020#include "base/enums.h"
Andreas Gampe170331f2017-12-07 18:41:03 -080021#include "base/logging.h" // For VLOG
Man Cao8c2ff642015-05-27 17:25:30 -070022#include "base/stl_util.h"
Mathieu Chartier9d156d52016-10-06 17:44:26 -070023#include "obj_ptr-inl.h"
Andreas Gampe5d08fcc2017-06-05 17:56:46 -070024#include "object_callbacks.h"
Man Cao8c2ff642015-05-27 17:25:30 -070025#include "stack.h"
26
Elliott Hughesf049a0b2018-10-25 14:28:12 -070027#include <android-base/properties.h>
Man Cao8c2ff642015-05-27 17:25:30 -070028
29namespace art {
30namespace gc {
31
32int32_t AllocRecordStackTraceElement::ComputeLineNumber() const {
33 DCHECK(method_ != nullptr);
34 return method_->GetLineNumFromDexPC(dex_pc_);
35}
36
Man Cao41656de2015-07-06 18:53:15 -070037const char* AllocRecord::GetClassDescriptor(std::string* storage) const {
38 // klass_ could contain null only if we implement class unloading.
Mathieu Chartiera7deef92016-02-22 14:49:04 -080039 return klass_.IsNull() ? "null" : klass_.Read()->GetDescriptor(storage);
Man Cao41656de2015-07-06 18:53:15 -070040}
41
Man Cao8c2ff642015-05-27 17:25:30 -070042void AllocRecordObjectMap::SetProperties() {
Bilyan Borisovbb661c02016-04-04 16:27:32 +010043#ifdef ART_TARGET_ANDROID
Man Cao8c2ff642015-05-27 17:25:30 -070044 // Check whether there's a system property overriding the max number of records.
45 const char* propertyName = "dalvik.vm.allocTrackerMax";
Elliott Hughesf049a0b2018-10-25 14:28:12 -070046 std::string allocMaxString = android::base::GetProperty(propertyName, "");
47 if (!allocMaxString.empty()) {
Man Cao8c2ff642015-05-27 17:25:30 -070048 char* end;
Elliott Hughesf049a0b2018-10-25 14:28:12 -070049 size_t value = strtoul(allocMaxString.c_str(), &end, 10);
Man Cao8c2ff642015-05-27 17:25:30 -070050 if (*end != '\0') {
51 LOG(ERROR) << "Ignoring " << propertyName << " '" << allocMaxString
52 << "' --- invalid";
53 } else {
54 alloc_record_max_ = value;
Man Cao1ed11b92015-06-11 22:47:35 -070055 if (recent_record_max_ > value) {
56 recent_record_max_ = value;
57 }
58 }
59 }
60 // Check whether there's a system property overriding the number of recent records.
61 propertyName = "dalvik.vm.recentAllocMax";
Elliott Hughesf049a0b2018-10-25 14:28:12 -070062 std::string recentAllocMaxString = android::base::GetProperty(propertyName, "");
63 if (!recentAllocMaxString.empty()) {
Man Cao1ed11b92015-06-11 22:47:35 -070064 char* end;
Elliott Hughesf049a0b2018-10-25 14:28:12 -070065 size_t value = strtoul(recentAllocMaxString.c_str(), &end, 10);
Man Cao1ed11b92015-06-11 22:47:35 -070066 if (*end != '\0') {
67 LOG(ERROR) << "Ignoring " << propertyName << " '" << recentAllocMaxString
68 << "' --- invalid";
69 } else if (value > alloc_record_max_) {
70 LOG(ERROR) << "Ignoring " << propertyName << " '" << recentAllocMaxString
71 << "' --- should be less than " << alloc_record_max_;
72 } else {
73 recent_record_max_ = value;
Man Cao8c2ff642015-05-27 17:25:30 -070074 }
75 }
76 // Check whether there's a system property overriding the max depth of stack trace.
Man Cao1ed11b92015-06-11 22:47:35 -070077 propertyName = "debug.allocTracker.stackDepth";
Elliott Hughesf049a0b2018-10-25 14:28:12 -070078 std::string stackDepthString = android::base::GetProperty(propertyName, "");
79 if (!stackDepthString.empty()) {
Man Cao8c2ff642015-05-27 17:25:30 -070080 char* end;
Elliott Hughesf049a0b2018-10-25 14:28:12 -070081 size_t value = strtoul(stackDepthString.c_str(), &end, 10);
Man Cao8c2ff642015-05-27 17:25:30 -070082 if (*end != '\0') {
83 LOG(ERROR) << "Ignoring " << propertyName << " '" << stackDepthString
84 << "' --- invalid";
Man Cao1ed11b92015-06-11 22:47:35 -070085 } else if (value > kMaxSupportedStackDepth) {
86 LOG(WARNING) << propertyName << " '" << stackDepthString << "' too large, using "
87 << kMaxSupportedStackDepth;
88 max_stack_depth_ = kMaxSupportedStackDepth;
Man Cao8c2ff642015-05-27 17:25:30 -070089 } else {
90 max_stack_depth_ = value;
91 }
92 }
Bilyan Borisovbb661c02016-04-04 16:27:32 +010093#endif // ART_TARGET_ANDROID
Man Cao8c2ff642015-05-27 17:25:30 -070094}
95
96AllocRecordObjectMap::~AllocRecordObjectMap() {
Mathieu Chartier14b0a5d2016-03-11 17:22:23 -080097 Clear();
Man Cao8c2ff642015-05-27 17:25:30 -070098}
99
Man Cao1ed11b92015-06-11 22:47:35 -0700100void AllocRecordObjectMap::VisitRoots(RootVisitor* visitor) {
101 CHECK_LE(recent_record_max_, alloc_record_max_);
102 BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(visitor, RootInfo(kRootDebugger));
103 size_t count = recent_record_max_;
Man Cao42c3c332015-06-23 16:38:25 -0700104 // Only visit the last recent_record_max_ number of allocation records in entries_ and mark the
105 // klass_ fields as strong roots.
Mathieu Chartiera7deef92016-02-22 14:49:04 -0800106 for (auto it = entries_.rbegin(), end = entries_.rend(); it != end; ++it) {
Mathieu Chartier458b1052016-03-29 14:02:55 -0700107 AllocRecord& record = it->second;
Mathieu Chartiera7deef92016-02-22 14:49:04 -0800108 if (count > 0) {
Mathieu Chartier458b1052016-03-29 14:02:55 -0700109 buffered_visitor.VisitRootIfNonNull(record.GetClassGcRoot());
Mathieu Chartiera7deef92016-02-22 14:49:04 -0800110 --count;
111 }
112 // Visit all of the stack frames to make sure no methods in the stack traces get unloaded by
113 // class unloading.
Mathieu Chartier458b1052016-03-29 14:02:55 -0700114 for (size_t i = 0, depth = record.GetDepth(); i < depth; ++i) {
115 const AllocRecordStackTraceElement& element = record.StackElement(i);
Mathieu Chartiera7deef92016-02-22 14:49:04 -0800116 DCHECK(element.GetMethod() != nullptr);
Andreas Gampe542451c2016-07-26 09:02:02 -0700117 element.GetMethod()->VisitRoots(buffered_visitor, kRuntimePointerSize);
Mathieu Chartiera7deef92016-02-22 14:49:04 -0800118 }
Man Cao42c3c332015-06-23 16:38:25 -0700119 }
120}
121
Mathieu Chartier97509952015-07-13 14:35:43 -0700122static inline void SweepClassObject(AllocRecord* record, IsMarkedVisitor* visitor)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700123 REQUIRES_SHARED(Locks::mutator_lock_)
Mathieu Chartier90443472015-07-16 20:32:27 -0700124 REQUIRES(Locks::alloc_tracker_lock_) {
Man Cao42c3c332015-06-23 16:38:25 -0700125 GcRoot<mirror::Class>& klass = record->GetClassGcRoot();
126 // This does not need a read barrier because this is called by GC.
127 mirror::Object* old_object = klass.Read<kWithoutReadBarrier>();
Mathieu Chartier97509952015-07-13 14:35:43 -0700128 if (old_object != nullptr) {
129 // The class object can become null if we implement class unloading.
130 // In that case we might still want to keep the class name string (not implemented).
131 mirror::Object* new_object = visitor->IsMarked(old_object);
132 DCHECK(new_object != nullptr);
133 if (UNLIKELY(old_object != new_object)) {
134 klass = GcRoot<mirror::Class>(new_object->AsClass());
135 }
Man Cao1ed11b92015-06-11 22:47:35 -0700136 }
137}
138
Mathieu Chartier97509952015-07-13 14:35:43 -0700139void AllocRecordObjectMap::SweepAllocationRecords(IsMarkedVisitor* visitor) {
Man Cao8c2ff642015-05-27 17:25:30 -0700140 VLOG(heap) << "Start SweepAllocationRecords()";
Man Cao42c3c332015-06-23 16:38:25 -0700141 size_t count_deleted = 0, count_moved = 0, count = 0;
142 // Only the first (size - recent_record_max_) number of records can be deleted.
Mathieu Chartiera7deef92016-02-22 14:49:04 -0800143 const size_t delete_bound = std::max(entries_.size(), recent_record_max_) - recent_record_max_;
Man Cao8c2ff642015-05-27 17:25:30 -0700144 for (auto it = entries_.begin(), end = entries_.end(); it != end;) {
Man Cao42c3c332015-06-23 16:38:25 -0700145 ++count;
Man Cao8c2ff642015-05-27 17:25:30 -0700146 // This does not need a read barrier because this is called by GC.
147 mirror::Object* old_object = it->first.Read<kWithoutReadBarrier>();
Mathieu Chartier458b1052016-03-29 14:02:55 -0700148 AllocRecord& record = it->second;
Mathieu Chartier97509952015-07-13 14:35:43 -0700149 mirror::Object* new_object = old_object == nullptr ? nullptr : visitor->IsMarked(old_object);
Man Cao8c2ff642015-05-27 17:25:30 -0700150 if (new_object == nullptr) {
Man Cao42c3c332015-06-23 16:38:25 -0700151 if (count > delete_bound) {
152 it->first = GcRoot<mirror::Object>(nullptr);
Mathieu Chartier458b1052016-03-29 14:02:55 -0700153 SweepClassObject(&record, visitor);
Man Cao42c3c332015-06-23 16:38:25 -0700154 ++it;
155 } else {
Man Cao42c3c332015-06-23 16:38:25 -0700156 it = entries_.erase(it);
157 ++count_deleted;
158 }
Man Cao8c2ff642015-05-27 17:25:30 -0700159 } else {
160 if (old_object != new_object) {
161 it->first = GcRoot<mirror::Object>(new_object);
162 ++count_moved;
163 }
Mathieu Chartier458b1052016-03-29 14:02:55 -0700164 SweepClassObject(&record, visitor);
Man Cao8c2ff642015-05-27 17:25:30 -0700165 ++it;
166 }
167 }
168 VLOG(heap) << "Deleted " << count_deleted << " allocation records";
169 VLOG(heap) << "Updated " << count_moved << " allocation records";
170}
171
Man Cao42c3c332015-06-23 16:38:25 -0700172void AllocRecordObjectMap::AllowNewAllocationRecords() {
Hiroshi Yamauchifdbd13c2015-09-02 16:16:58 -0700173 CHECK(!kUseReadBarrier);
Man Cao42c3c332015-06-23 16:38:25 -0700174 allow_new_record_ = true;
175 new_record_condition_.Broadcast(Thread::Current());
176}
177
178void AllocRecordObjectMap::DisallowNewAllocationRecords() {
Hiroshi Yamauchifdbd13c2015-09-02 16:16:58 -0700179 CHECK(!kUseReadBarrier);
Man Cao42c3c332015-06-23 16:38:25 -0700180 allow_new_record_ = false;
181}
182
Hiroshi Yamauchifdbd13c2015-09-02 16:16:58 -0700183void AllocRecordObjectMap::BroadcastForNewAllocationRecords() {
Hiroshi Yamauchifdbd13c2015-09-02 16:16:58 -0700184 new_record_condition_.Broadcast(Thread::Current());
185}
186
Man Cao8c2ff642015-05-27 17:25:30 -0700187void AllocRecordObjectMap::SetAllocTrackingEnabled(bool enable) {
188 Thread* self = Thread::Current();
189 Heap* heap = Runtime::Current()->GetHeap();
190 if (enable) {
191 {
192 MutexLock mu(self, *Locks::alloc_tracker_lock_);
193 if (heap->IsAllocTrackingEnabled()) {
194 return; // Already enabled, bail.
195 }
Mathieu Chartier14b0a5d2016-03-11 17:22:23 -0800196 AllocRecordObjectMap* records = heap->GetAllocationRecords();
197 if (records == nullptr) {
198 records = new AllocRecordObjectMap;
199 heap->SetAllocationRecords(records);
200 }
Man Cao8c2ff642015-05-27 17:25:30 -0700201 CHECK(records != nullptr);
202 records->SetProperties();
203 std::string self_name;
204 self->GetThreadName(self_name);
205 if (self_name == "JDWP") {
206 records->alloc_ddm_thread_id_ = self->GetTid();
207 }
208 size_t sz = sizeof(AllocRecordStackTraceElement) * records->max_stack_depth_ +
209 sizeof(AllocRecord) + sizeof(AllocRecordStackTrace);
210 LOG(INFO) << "Enabling alloc tracker (" << records->alloc_record_max_ << " entries of "
211 << records->max_stack_depth_ << " frames, taking up to "
212 << PrettySize(sz * records->alloc_record_max_) << ")";
Man Cao8c2ff642015-05-27 17:25:30 -0700213 }
214 Runtime::Current()->GetInstrumentation()->InstrumentQuickAllocEntryPoints();
Mathieu Chartier16e51be2016-02-23 10:37:32 -0800215 {
216 MutexLock mu(self, *Locks::alloc_tracker_lock_);
217 heap->SetAllocTrackingEnabled(true);
218 }
Man Cao8c2ff642015-05-27 17:25:30 -0700219 } else {
Mathieu Chartier0b8b4a62016-03-02 12:52:37 -0800220 // Delete outside of the critical section to avoid possible lock violations like the runtime
221 // shutdown lock.
Man Cao8c2ff642015-05-27 17:25:30 -0700222 {
223 MutexLock mu(self, *Locks::alloc_tracker_lock_);
224 if (!heap->IsAllocTrackingEnabled()) {
225 return; // Already disabled, bail.
226 }
227 heap->SetAllocTrackingEnabled(false);
228 LOG(INFO) << "Disabling alloc tracker";
Mathieu Chartier14b0a5d2016-03-11 17:22:23 -0800229 AllocRecordObjectMap* records = heap->GetAllocationRecords();
230 records->Clear();
Man Cao8c2ff642015-05-27 17:25:30 -0700231 }
232 // If an allocation comes in before we uninstrument, we will safely drop it on the floor.
233 Runtime::Current()->GetInstrumentation()->UninstrumentQuickAllocEntryPoints();
234 }
235}
236
Mathieu Chartier458b1052016-03-29 14:02:55 -0700237void AllocRecordObjectMap::RecordAllocation(Thread* self,
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700238 ObjPtr<mirror::Object>* obj,
Man Cao42c3c332015-06-23 16:38:25 -0700239 size_t byte_count) {
Mathieu Chartier458b1052016-03-29 14:02:55 -0700240 // Get stack trace outside of lock in case there are allocations during the stack walk.
241 // b/27858645.
242 AllocRecordStackTrace trace;
Mathieu Chartier458b1052016-03-29 14:02:55 -0700243 {
244 StackHandleScope<1> hs(self);
245 auto obj_wrapper = hs.NewHandleWrapper(obj);
Andreas Gampec7d878d2018-11-19 18:42:06 +0000246
247 StackVisitor::WalkStack(
248 [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
249 if (trace.GetDepth() >= max_stack_depth_) {
250 return false;
251 }
252 ArtMethod* m = stack_visitor->GetMethod();
253 // m may be null if we have inlined methods of unresolved classes. b/27858645
254 if (m != nullptr && !m->IsRuntimeMethod()) {
255 m = m->GetInterfaceMethodIfProxy(kRuntimePointerSize);
256 trace.AddStackElement(AllocRecordStackTraceElement(m, stack_visitor->GetDexPc()));
257 }
258 return true;
259 },
260 self,
261 /* context= */ nullptr,
262 art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
Mathieu Chartier458b1052016-03-29 14:02:55 -0700263 }
264
Man Cao8c2ff642015-05-27 17:25:30 -0700265 MutexLock mu(self, *Locks::alloc_tracker_lock_);
Mathieu Chartier458b1052016-03-29 14:02:55 -0700266 Heap* const heap = Runtime::Current()->GetHeap();
Man Cao8c2ff642015-05-27 17:25:30 -0700267 if (!heap->IsAllocTrackingEnabled()) {
268 // In the process of shutting down recording, bail.
269 return;
270 }
271
Mathieu Chartier458b1052016-03-29 14:02:55 -0700272 // Do not record for DDM thread.
273 if (alloc_ddm_thread_id_ == self->GetTid()) {
Man Cao8c2ff642015-05-27 17:25:30 -0700274 return;
275 }
276
Roland Levillainaf290312018-02-27 20:02:17 +0000277 // Wait for GC's sweeping to complete and allow new records.
Mathieu Chartier458b1052016-03-29 14:02:55 -0700278 while (UNLIKELY((!kUseReadBarrier && !allow_new_record_) ||
Hiroshi Yamauchi0b713572015-06-16 18:29:23 -0700279 (kUseReadBarrier && !self->GetWeakRefAccessEnabled()))) {
Hiroshi Yamauchi30493242016-11-03 13:06:52 -0700280 // Check and run the empty checkpoint before blocking so the empty checkpoint will work in the
281 // presence of threads blocking for weak ref access.
Hiroshi Yamauchia2224042017-02-08 16:35:45 -0800282 self->CheckEmptyCheckpointFromWeakRefAccess(Locks::alloc_tracker_lock_);
Mathieu Chartier458b1052016-03-29 14:02:55 -0700283 new_record_condition_.WaitHoldingLocks(self);
Man Cao42c3c332015-06-23 16:38:25 -0700284 }
285
Hiroshi Yamauchi6f0c6cd2016-03-18 17:17:52 -0700286 if (!heap->IsAllocTrackingEnabled()) {
287 // Return if the allocation tracking has been disabled while waiting for system weak access
288 // above.
289 return;
290 }
291
Mathieu Chartier458b1052016-03-29 14:02:55 -0700292 DCHECK_LE(Size(), alloc_record_max_);
Man Cao8c2ff642015-05-27 17:25:30 -0700293
Mathieu Chartier458b1052016-03-29 14:02:55 -0700294 // Erase extra unfilled elements.
295 trace.SetTid(self->GetTid());
Man Cao8c2ff642015-05-27 17:25:30 -0700296
Mathieu Chartier458b1052016-03-29 14:02:55 -0700297 // Add the record.
Mathieu Chartier9d156d52016-10-06 17:44:26 -0700298 Put(obj->Ptr(), AllocRecord(byte_count, (*obj)->GetClass(), std::move(trace)));
Mathieu Chartier458b1052016-03-29 14:02:55 -0700299 DCHECK_LE(Size(), alloc_record_max_);
Man Cao8c2ff642015-05-27 17:25:30 -0700300}
301
Mathieu Chartier14b0a5d2016-03-11 17:22:23 -0800302void AllocRecordObjectMap::Clear() {
Mathieu Chartier14b0a5d2016-03-11 17:22:23 -0800303 entries_.clear();
304}
305
Mathieu Chartier458b1052016-03-29 14:02:55 -0700306AllocRecordObjectMap::AllocRecordObjectMap()
307 : new_record_condition_("New allocation record condition", *Locks::alloc_tracker_lock_) {}
308
Man Cao8c2ff642015-05-27 17:25:30 -0700309} // namespace gc
310} // namespace art