首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 系统运维 >

System.gc初始分析

2012-11-10 
System.gc初步分析???? openjdk中的垃圾回收是一个庞大的课题,如何标记活动的对象,就涉及到了堆栈的、常量

System.gc初步分析

???? openjdk中的垃圾回收是一个庞大的课题,如何标记活动的对象,就涉及到了堆栈的、常量池的跟踪标记等,非常复杂。在此先做一个初步的分析。

???? 先从System.java中的gc方法开始阅读。

???? public static void gc() {
??????? Runtime.getRuntime().gc();
???? }

???? 跟踪进去,其实调用到了jvm.cpp里面的JVM_GC(void)

??? {

????????????? if (!DisableExplicitGC) { //如果可以直接进行垃圾回收,则执行下面的一步, -XX:+DisableExplicitGC?选项可以关闭jvm的直接垃圾回收

???????????????????? Universe::heap()->collect(GCCause::_java_lang_system_gc);
????????????? }

???? }

???? 垃圾回收的方式有多种,下面跟踪并发收集(ParallelScavengeHeap.cpp)。

???? void ParallelScavengeHeap::collect(GCCause::Cause cause) {

???????????? ...........

?????????????VM_ParallelGCSystemGC op(gc_count, full_gc_count, cause);
?????????????VMThread::execute(&op);

???? }

?????上面的exceute()方法,主要执行的是VM_ParallelGCSystemGC 的doit()方法,下面看看

???? void VM_ParallelGCSystemGC::doit() {

???????????? //在这主要看一下全部回收的代码

?????????????ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();

?????????????heap->invoke_full_gc(false);

???? }

?????下面是invoke_full_gc代码

???? inline void ParallelScavengeHeap::invoke_full_gc(bool maximum_compaction)
??? {

???????????? .......
???????????? PSMarkSweep::invoke(maximum_compaction);//从名字看出这个方法主要做标记、清除操作
???? }

???? 跟踪进入上面方法

???? void PSMarkSweep::invoke(bool maximum_heap_compaction) {

??????????? .........

??????????? PSMarkSweep::invoke_no_policy(maximum_heap_compaction);

???? }
???? 上面invoke_no_policy非常复杂,在这仅对其第一阶段的操作进行简单分析。

???? void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {

??????????? .........

??????????? //从根开始对强引用开始进行标记操作

????????????Universe::oops_do(mark_and_push_closure());
????????????ReferenceProcessor::oops_do(mark_and_push_closure());
??????????? JNIHandles::oops_do(mark_and_push_closure());?? // Global (strong) JNI handles

??????????? //跟踪每个线程堆栈,对堆栈里面的对象引用进行跟踪
??????????? Threads::oops_do(mark_and_push_closure());
??????????? ObjectSynchronizer::oops_do(mark_and_push_closure());
??????????? FlatProfiler::oops_do(mark_and_push_closure());
??????????? Management::oops_do(mark_and_push_closure());
??????????? JvmtiExport::oops_do(mark_and_push_closure());

????????????//跟踪常量池用到的每个类
??????????? SystemDictionary::always_strong_oops_do(mark_and_push_closure());
??????????? vmSymbols::oops_do(mark_and_push_closure());

???? }

???? 简单提一下,上面用到的MarkAndPushClosure,它其实就是将对象打上标志,并将对象指针压入一个栈中。采用的是回调函数用法,由上面的oops_do调用。代码如下

???? {

????????????if (!oopDesc::is_null(heap_oop)) {
?????????????????? oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
????????????????? if (!obj->mark()->is_marked()) {
????????????????????????? mark_object(obj);? //对遍历到的对象进行标志
???????????????????????? _marking_stack->push(obj);?//对象入栈
???????????????? }

??????????? }
?????}

?????好,回到前面,简单分析一下Threads::oops_do(mark_and_push_closure())。

???? void Threads::oops_do(OopClosure* f) {

?????????? for (JavaThread*?p = _thread_list; p;?p = X->next()){ //遍历所有用户线程

?????????????????? p->oops_do(f);

????????? }

????????? VMThread::vm_thread()->oops_do(f); //遍历vmThread

???? }
???? java对象的方法调用,其在方法内创建的局部变量都在线程堆栈内。javaThread::oops_do应该会对堆栈内的对象进行标记,下面看一下代码。

??? void JavaThread::oops_do(OopClosure* f) {

???????????Thread::oops_do(f);

?????????? ........

?????????? //下面是堆栈桢的遍历

???????????for(StackFrameStream fst(this); !fst.is_done(); fst.next()) {
?????????????????? fst.current()->oops_do(f, fst.register_map());
?????????? }

?????????? ........

??? }

????void? Frame::oops_do(OopClosure* f, RegisterMap* map) {

?????????? oops_do_internal(f, map, true);

??? }

??? void frame::oops_do_internal(OopClosure* f, RegisterMap* map, bool use_interpreter_oop_map_cache) {

?????????? if (is_interpreted_frame())??? { //以解释桢为例

?????????????? oops_interpreted_do(f, map, use_interpreter_oop_map_cache);

??????????? }

?? }

???void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool query_oop_map_cache) {

??????????............

?????????? oops_interpreted_locals_do(f, max_locals, mask);
??? oops_interpreted_expressions_do(f, signature, is_static,
??????????????????????????????????? m->max_stack(),
??????????????????????????????????? max_locals, mask);

?????????............

? }

??void frame::oops_interpreted_locals_do(OopClosure *f,
????????????????????????????????????? int max_locals,
????????????????????????????????????? InterpreterOopMap *mask) {

????????? for (int i = 0; i < max_locals; i++ ) {
????????????????? Tag tag = interpreter_frame_local_tag(i);
????????????????? if (tag == TagReference) { //如果是对象引用,则进行标记,总算找到了
????????????????????????? oop* addr = (oop*) interpreter_frame_local_at(i);
????????????????????????? assert((intptr_t*)addr >= sp(), "must be inside the frame");
??????????????????????????f->do_oop(addr);
??????? ??? }

?}

?堆栈里面存着基本类型及引用类型,它们的位置及垃圾回收算法是如何区分这些类型的,这个还需要进一步的分析。

热点排行