Hotspot GC Root 对应调用链
GC Root
GC Root全稱是garbage collection root, 即垃圾回收的根. 回到我們的葡萄比喻上來, 也就是一串葡萄的柄. 實際上JVM中的GC Root不只一個, 也就是多個這樣的 “柄”.
?
來看看hotspot網站的解釋:
garbage collection root
A pointer into the Java object heap from outside the heap. These come up, e.g., from static fields of classes, local references in activation frames, etc.
官網的解釋是由heap外部指向heap內的對象的指針, 比如class的靜態字段, 活躍棧幀里的本地引用等. 這里有點小疑問, 從代碼上來看, 靜態字段也是存在于heap對象(Class對象)中的, 這樣來看, 按照heap外指針的定義來解釋好像不太妥當. 可以先不關注這個問題, 等會我們從代碼上來直觀感受一下.
這個說法可能聽起來有點奇怪, 因為GC Root的存在是客觀的, 并不是因為需要, 這里的意思更多的是為什么要單獨提出這么一個概念. 前面介紹過, 對象之間的相互引用會形成一個圖(graph), 而要遍歷存活的對象, 必須從一些點出發, 這些點, 就是GC Root了.
這樣做的目的避免有閉環的出現,閉環的出現講師災難性,大大影響性能。
最為GC Root四種對象:
?
- 虛擬機棧中的引用對象
- 方法區中類靜態屬性引用的對象
- 方法區中常量引用對象
- 本地方法棧中JNI引用對象
GC Root 遍歷的源碼:
void GenCollectedHeap::process_roots(StrongRootsScope* scope,ScanningOption so,OopClosure* strong_roots,OopClosure* weak_roots,CLDClosure* strong_cld_closure,CLDClosure* weak_cld_closure,CodeBlobToOopClosure* code_roots) {// General roots.assert(Threads::thread_claim_parity() != 0, "must have called prologue code");assert(code_roots != NULL, "code root closure should always be set");// _n_termination for _process_strong_tasks should be set up stream// in a method not running in a GC worker. Otherwise the GC worker// could be trying to change the termination condition while the task// is executing in another GC worker.if (!_process_strong_tasks->is_task_claimed(GCH_PS_ClassLoaderDataGraph_oops_do)) {ClassLoaderDataGraph::roots_cld_do(strong_cld_closure, weak_cld_closure);}// Only process code roots from thread stacks if we aren't visiting the entire CodeCache anywayCodeBlobToOopClosure* roots_from_code_p = (so & SO_AllCodeCache) ? NULL : code_roots;bool is_par = scope->n_threads() > 1;Threads::possibly_parallel_oops_do(is_par, strong_roots, roots_from_code_p);if (!_process_strong_tasks->is_task_claimed(GCH_PS_Universe_oops_do)) {Universe::oops_do(strong_roots);}// Global (strong) JNI handlesif (!_process_strong_tasks->is_task_claimed(GCH_PS_JNIHandles_oops_do)) {JNIHandles::oops_do(strong_roots);}if (!_process_strong_tasks->is_task_claimed(GCH_PS_ObjectSynchronizer_oops_do)) {ObjectSynchronizer::oops_do(strong_roots);}if (!_process_strong_tasks->is_task_claimed(GCH_PS_FlatProfiler_oops_do)) {FlatProfiler::oops_do(strong_roots);}if (!_process_strong_tasks->is_task_claimed(GCH_PS_Management_oops_do)) {Management::oops_do(strong_roots);}if (!_process_strong_tasks->is_task_claimed(GCH_PS_jvmti_oops_do)) {JvmtiExport::oops_do(strong_roots);}if (!_process_strong_tasks->is_task_claimed(GCH_PS_SystemDictionary_oops_do)) {SystemDictionary::roots_oops_do(strong_roots, weak_roots);}// All threads execute the following. A specific chunk of buckets// from the StringTable are the individual tasks.if (weak_roots != NULL) {if (is_par) {StringTable::possibly_parallel_oops_do(weak_roots);} else {StringTable::oops_do(weak_roots);}}if (!_process_strong_tasks->is_task_claimed(GCH_PS_CodeCache_oops_do)) {if (so & SO_ScavengeCodeCache) {assert(code_roots != NULL, "must supply closure for code cache");// We only visit parts of the CodeCache when scavenging.CodeCache::scavenge_root_nmethods_do(code_roots);}if (so & SO_AllCodeCache) {assert(code_roots != NULL, "must supply closure for code cache");// CMSCollector uses this to do intermediate-strength collections.// We scan the entire code cache, since CodeCache::do_unloading is not called.CodeCache::blobs_do(code_roots);}// Verify that the code cache contents are not subject to// movement by a scavenging collection.DEBUG_ONLY(CodeBlobToOopClosure assert_code_is_non_scavengable(&assert_is_non_scavengable_closure, !CodeBlobToOopClosure::FixRelocations));DEBUG_ONLY(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable));} }http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/gc_implementation/
上面是hotspot1.7(openjdk)源代碼
標記存活對象的處理主要在markSweep.cpp
/** Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.** This code is free software; you can redistribute it and/or modify it* under the terms of the GNU General Public License version 2 only, as* published by the Free Software Foundation.** This code is distributed in the hope that it will be useful, but WITHOUT* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License* version 2 for more details (a copy is included in the LICENSE file that* accompanied this code).** You should have received a copy of the GNU General Public License version* 2 along with this work; if not, write to the Free Software Foundation,* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.** Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA* or visit www.oracle.com if you need additional information or have any* questions.**/#include "precompiled.hpp" #include "compiler/compileBroker.hpp" #include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "oops/methodDataOop.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/oop.inline.hpp"Stack<oop> MarkSweep::_marking_stack; Stack<DataLayout*> MarkSweep::_revisit_mdo_stack; Stack<Klass*> MarkSweep::_revisit_klass_stack; Stack<ObjArrayTask> MarkSweep::_objarray_stack;Stack<oop> MarkSweep::_preserved_oop_stack; Stack<markOop> MarkSweep::_preserved_mark_stack; size_t MarkSweep::_preserved_count = 0; size_t MarkSweep::_preserved_count_max = 0; PreservedMark* MarkSweep::_preserved_marks = NULL; ReferenceProcessor* MarkSweep::_ref_processor = NULL;#ifdef VALIDATE_MARK_SWEEP GrowableArray<void*>* MarkSweep::_root_refs_stack = NULL; GrowableArray<oop> * MarkSweep::_live_oops = NULL; GrowableArray<oop> * MarkSweep::_live_oops_moved_to = NULL; GrowableArray<size_t>* MarkSweep::_live_oops_size = NULL; size_t MarkSweep::_live_oops_index = 0; size_t MarkSweep::_live_oops_index_at_perm = 0; GrowableArray<void*>* MarkSweep::_other_refs_stack = NULL; GrowableArray<void*>* MarkSweep::_adjusted_pointers = NULL; bool MarkSweep::_pointer_tracking = false; bool MarkSweep::_root_tracking = true;GrowableArray<HeapWord*>* MarkSweep::_cur_gc_live_oops = NULL; GrowableArray<HeapWord*>* MarkSweep::_cur_gc_live_oops_moved_to = NULL; GrowableArray<size_t> * MarkSweep::_cur_gc_live_oops_size = NULL; GrowableArray<HeapWord*>* MarkSweep::_last_gc_live_oops = NULL; GrowableArray<HeapWord*>* MarkSweep::_last_gc_live_oops_moved_to = NULL; GrowableArray<size_t> * MarkSweep::_last_gc_live_oops_size = NULL; #endifvoid MarkSweep::revisit_weak_klass_link(Klass* k) {_revisit_klass_stack.push(k); }void MarkSweep::follow_weak_klass_links() {// All klasses on the revisit stack are marked at this point.// Update and follow all subklass, sibling and implementor links.if (PrintRevisitStats) {gclog_or_tty->print_cr("#classes in system dictionary = %d",SystemDictionary::number_of_classes());gclog_or_tty->print_cr("Revisit klass stack size = " SIZE_FORMAT,_revisit_klass_stack.size());}while (!_revisit_klass_stack.is_empty()) {Klass* const k = _revisit_klass_stack.pop();k->follow_weak_klass_links(&is_alive, &keep_alive);}follow_stack(); }void MarkSweep::revisit_mdo(DataLayout* p) {_revisit_mdo_stack.push(p); }void MarkSweep::follow_mdo_weak_refs() {// All strongly reachable oops have been marked at this point;// we can visit and clear any weak references from MDO's which// we memoized during the strong marking phase.assert(_marking_stack.is_empty(), "Marking stack should be empty");if (PrintRevisitStats) {gclog_or_tty->print_cr("#classes in system dictionary = %d",SystemDictionary::number_of_classes());gclog_or_tty->print_cr("Revisit MDO stack size = " SIZE_FORMAT,_revisit_mdo_stack.size());}while (!_revisit_mdo_stack.is_empty()) {_revisit_mdo_stack.pop()->follow_weak_refs(&is_alive);}follow_stack(); }MarkSweep::FollowRootClosure MarkSweep::follow_root_closure; CodeBlobToOopClosure MarkSweep::follow_code_root_closure(&MarkSweep::follow_root_closure, /*do_marking=*/ true);void MarkSweep::FollowRootClosure::do_oop(oop* p) { follow_root(p); } void MarkSweep::FollowRootClosure::do_oop(narrowOop* p) { follow_root(p); }MarkSweep::MarkAndPushClosure MarkSweep::mark_and_push_closure;void MarkSweep::MarkAndPushClosure::do_oop(oop* p) { assert(*p == NULL || (*p)->is_oop(), ""); mark_and_push(p); } void MarkSweep::MarkAndPushClosure::do_oop(narrowOop* p) { mark_and_push(p); }void MarkSweep::follow_stack() {do {while (!_marking_stack.is_empty()) {oop obj = _marking_stack.pop();assert (obj->is_gc_marked(), "p must be marked");obj->follow_contents();}// Process ObjArrays one at a time to avoid marking stack bloat.if (!_objarray_stack.is_empty()) {ObjArrayTask task = _objarray_stack.pop();objArrayKlass* const k = (objArrayKlass*)task.obj()->blueprint();k->oop_follow_contents(task.obj(), task.index());}} while (!_marking_stack.is_empty() || !_objarray_stack.is_empty()); }MarkSweep::FollowStackClosure MarkSweep::follow_stack_closure;void MarkSweep::FollowStackClosure::do_void() { follow_stack(); }// We preserve the mark which should be replaced at the end and the location // that it will go. Note that the object that this markOop belongs to isn't // currently at that address but it will be after phase4 void MarkSweep::preserve_mark(oop obj, markOop mark) {// We try to store preserved marks in the to space of the new generation since// this is storage which should be available. Most of the time this should be// sufficient space for the marks we need to preserve but if it isn't we fall// back to using Stacks to keep track of the overflow.if (_preserved_count < _preserved_count_max) {_preserved_marks[_preserved_count++].init(obj, mark);} else {_preserved_mark_stack.push(mark);_preserved_oop_stack.push(obj);} }MarkSweep::AdjustPointerClosure MarkSweep::adjust_root_pointer_closure(true); MarkSweep::AdjustPointerClosure MarkSweep::adjust_pointer_closure(false);void MarkSweep::AdjustPointerClosure::do_oop(oop* p) { adjust_pointer(p, _is_root); } void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p, _is_root); }void MarkSweep::adjust_marks() {assert( _preserved_oop_stack.size() == _preserved_mark_stack.size(),"inconsistent preserved oop stacks");// adjust the oops we saved earlierfor (size_t i = 0; i < _preserved_count; i++) {_preserved_marks[i].adjust_pointer();}// deal with the overflow stackStackIterator<oop> iter(_preserved_oop_stack);while (!iter.is_empty()) {oop* p = iter.next_addr();adjust_pointer(p);} }void MarkSweep::restore_marks() {assert(_preserved_oop_stack.size() == _preserved_mark_stack.size(),"inconsistent preserved oop stacks");if (PrintGC && Verbose) {gclog_or_tty->print_cr("Restoring %d marks",_preserved_count + _preserved_oop_stack.size());}// restore the marks we saved earlierfor (size_t i = 0; i < _preserved_count; i++) {_preserved_marks[i].restore();}// deal with the overflowwhile (!_preserved_oop_stack.is_empty()) {oop obj = _preserved_oop_stack.pop();markOop mark = _preserved_mark_stack.pop();obj->set_mark(mark);} }#ifdef VALIDATE_MARK_SWEEPvoid MarkSweep::track_adjusted_pointer(void* p, bool isroot) {if (!ValidateMarkSweep)return;if (!isroot) {if (_pointer_tracking) {guarantee(_adjusted_pointers->contains(p), "should have seen this pointer");_adjusted_pointers->remove(p);}} else {ptrdiff_t index = _root_refs_stack->find(p);if (index != -1) {int l = _root_refs_stack->length();if (l > 0 && l - 1 != index) {void* last = _root_refs_stack->pop();assert(last != p, "should be different");_root_refs_stack->at_put(index, last);} else {_root_refs_stack->remove(p);}}} }void MarkSweep::check_adjust_pointer(void* p) {_adjusted_pointers->push(p); }class AdjusterTracker: public OopClosure {public:AdjusterTracker() {}void do_oop(oop* o) { MarkSweep::check_adjust_pointer(o); }void do_oop(narrowOop* o) { MarkSweep::check_adjust_pointer(o); } };void MarkSweep::track_interior_pointers(oop obj) {if (ValidateMarkSweep) {_adjusted_pointers->clear();_pointer_tracking = true;AdjusterTracker checker;obj->oop_iterate(&checker);} }void MarkSweep::check_interior_pointers() {if (ValidateMarkSweep) {_pointer_tracking = false;guarantee(_adjusted_pointers->length() == 0, "should have processed the same pointers");} }void MarkSweep::reset_live_oop_tracking(bool at_perm) {if (ValidateMarkSweep) {guarantee((size_t)_live_oops->length() == _live_oops_index, "should be at end of live oops");_live_oops_index = at_perm ? _live_oops_index_at_perm : 0;} }void MarkSweep::register_live_oop(oop p, size_t size) {if (ValidateMarkSweep) {_live_oops->push(p);_live_oops_size->push(size);_live_oops_index++;} }這個類中關鍵的數據是:
GrowableArray<oop> * MarkSweep::_live_oops = NULL; GrowableArray<oop> * MarkSweep::_live_oops_moved_to = NULL;看下GrowableArray 源碼:
/** Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.** This code is free software; you can redistribute it and/or modify it* under the terms of the GNU General Public License version 2 only, as* published by the Free Software Foundation.** This code is distributed in the hope that it will be useful, but WITHOUT* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License* version 2 for more details (a copy is included in the LICENSE file that* accompanied this code).** You should have received a copy of the GNU General Public License version* 2 along with this work; if not, write to the Free Software Foundation,* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.** Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA* or visit www.oracle.com if you need additional information or have any* questions.**/#include "precompiled.hpp" #include "memory/resourceArea.hpp" #include "utilities/growableArray.hpp" #ifdef TARGET_OS_FAMILY_linux # include "thread_linux.inline.hpp" #endif #ifdef TARGET_OS_FAMILY_solaris # include "thread_solaris.inline.hpp" #endif #ifdef TARGET_OS_FAMILY_windows # include "thread_windows.inline.hpp" #endif #ifdef ASSERT void GenericGrowableArray::set_nesting() {if (on_stack()) {_nesting = Thread::current()->resource_area()->nesting();} }void GenericGrowableArray::check_nesting() {// Check for insidious allocation bug: if a GrowableArray overflows, the// grown array must be allocated under the same ResourceMark as the original.// Otherwise, the _data array will be deallocated too early.if (on_stack() &&_nesting != Thread::current()->resource_area()->nesting()) {fatal("allocation bug: GrowableArray could grow within nested ResourceMark");} } #endifvoid* GenericGrowableArray::raw_allocate(int elementSize) {assert(_max >= 0, "integer overflow");size_t byte_size = elementSize * (size_t) _max;if (on_stack()) {return (void*)resource_allocate_bytes(byte_size);} else if (on_C_heap()) {return (void*)AllocateHeap(byte_size, "GrET in " __FILE__);} else {return _arena->Amalloc(byte_size);} }可以見得,標記存活的對象最后會放到一個二維數組里面,也就是指向存活的對象的指針放在一張連續的二維數組的地址塊內。
這塊地址區域就是極為重要的地址!
但是是如何一步步標記的呢?
?
?
總結
以上是生活随笔為你收集整理的Hotspot GC Root 对应调用链的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 魔兽世界怀旧服赞吉尔之触任务在哪里 赞吉
- 下一篇: Swift 中的关键字详解