//art/runtime/hprof/hprof.cc voidDumpHeap(constchar* filename, int fd, bool direct_to_ddms){ CHECK(filename != nullptr); Thread* self = Thread::Current(); // Need to take a heap dump while GC isn't running. See the comment in Heap::VisitObjects(). // Also we need the critical section to avoid visiting the same object twice. See b/34967844 // 此时需要停止所有进程等待dump文件完成 gc::ScopedGCCriticalSection gcs(self, gc::kGcCauseHprof, gc::kCollectorTypeHprof); ScopedSuspendAll ssa(__FUNCTION__, true/* long suspend */); Hprof hprof(filename, fd, direct_to_ddms); hprof.Dump(); }
voidDump() REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::heap_bitmap_lock_, !Locks::alloc_tracker_lock_){ ... // First pass to measure the size of the dump. size_t overall_size; size_t max_length; { EndianOutput count_output; output_ = &count_output; ProcessHeap(false);//执行heap读取 overall_size = count_output.SumLength(); max_length = count_output.MaxLength(); output_ = nullptr; }
SuspendAllInternal(self, self); // All threads are known to have suspended (but a thread may still own the mutator lock) // Make sure this thread grabs exclusive access to the mutator lock and its protected data. }
// Must install the pending_threads counter first, then check thread->IsSuspend() and clear // the counter. Otherwise there's a race with Thread::TransitionFromRunnableToSuspended() // that can lead a thread to miss a call to PassActiveSuspendBarriers(). if (thread->IsSuspended()) { // Only clear the counter for the current thread. thread->ClearSuspendBarrier(&pending_threads); pending_threads.FetchAndSubSequentiallyConsistent(1); } }
Locks::mutator_lock_->ExclusiveUnlock(self); { MutexLock mu(self, *Locks::thread_list_lock_); MutexLock mu2(self, *Locks::thread_suspend_count_lock_); // Update global suspend all state for attaching threads. --suspend_all_count_; // Decrement the suspend counts for all threads. for (constauto& thread : list_) { if (thread == self) { continue; } //解除suspend状态 bool updated = thread->ModifySuspendCount(self, -1, nullptr, SuspendReason::kInternal); DCHECK(updated); }
// Broadcast a notification to all suspended threads, some or all of // which may choose to wake up. No need to wait for them. if (self != nullptr) { VLOG(threads) << *self << " ResumeAll waking others"; } else { VLOG(threads) << "Thread[null] ResumeAll waking others"; } Thread::resume_cond_->Broadcast(self); }
voidProcessHeader(bool string_first)REQUIRES(Locks::mutator_lock_){ // Write the header. WriteFixedHeader(); // Write the string and class tables, and any stack traces, to the header. // (jhat requires that these appear before any of the data in the body that refers to them.) // jhat also requires the string table appear before class table and stack traces. // However, WriteStackTraces() can modify the string table, so it's necessary to call // WriteStringTable() last in the first pass, to compute the correct length of the output. if (string_first) { WriteStringTable(); } WriteClassTable(); WriteStackTraces(); if (!string_first) { WriteStringTable(); } output_->EndRecord(); }
WriteFixedHeader
生成Hprof Header
WriteClassTable
生成Tag为LOAD_CLASS的Record
WriteStackTraces
生成Tag为STACK_FRAME和STACK_TRACE的Record
WriteStringTable
生成Tag为String的Record
ProcessBody()
主要为了生成Tag为HEAP_DUMP_SEGMENT和HEAP_DUMP_END的Record。
还有生成HEAP_DUMP_SEGMENT下的子Record。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
voidProcessBody()REQUIRES(Locks::mutator_lock_){ Runtime* const runtime = Runtime::Current(); // Walk the roots and the heap. output_->StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, kHprofTime);
// This object is in a different heap than the current one. // Emit a HEAP_DUMP_INFO tag to change heaps. __ AddU1(HPROF_HEAP_DUMP_INFO); __ AddU4(static_cast<uint32_t>(heap_type)); // uint32_t: heap type switch (heap_type) { case HPROF_HEAP_APP: nameId = LookupStringId("app"); break; case HPROF_HEAP_ZYGOTE: nameId = LookupStringId("zygote"); break; case HPROF_HEAP_IMAGE: nameId = LookupStringId("image"); break; default: // Internal error LOG(ERROR) << "Unexpected desiredHeap"; nameId = LookupStringId("<ILLEGAL>"); break; } __ AddStringId(nameId); current_heap_ = heap_type; }
mirror::Class* c = obj->GetClass(); if (c == nullptr) { // This object will bother HprofReader, because it has a null // class, so just don't dump it. It could be // gDvm.unlinkedJavaLangClass or it could be an object just // allocated which hasn't been initialized yet. } else { if (obj->IsClass()) { DumpHeapClass(obj->AsClass()); } elseif (c->IsArrayClass()) { DumpHeapArray(obj->AsArray(), c); } else { DumpHeapInstanceObject(obj, c, visitor.GetRoots()); } }