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);
            }

 }

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: `System.gc()` 是 Java 程序中的一个方法,它是在 Java 的 `java.lang` 包中的。这个方法的作用是请求 JVM 进行垃圾回收,但并不保证 JVM 一定会立即回收垃圾。它只是一个建议,由 JVM 决定是否执行回收操作。实际上,现代的 JVM 实现已经很智能,不需要开发人员明确地调用此方法来进行垃圾回收。 ### 回答2: System.gc();是Java中的一个方法调用,用于显示地触发垃圾回收。垃圾回收是Java虚拟机在运行时自动管理内存的一种机制,它负责自动回收不再被使用的对象的内存空间。当程序运行时,创建了一些对象,并且这些对象不再被引用时,Java虚拟机会自动回收这些对象所占用的内存空间,释放资源,这个过程就是垃圾回收。 而System.gc()方法的作用就是显式地调用垃圾回收器。虽然Java虚拟机会根据自身的策略自动触发垃圾回收,但是我们也可以通过调用System.gc()方法来建议虚拟机执行垃圾回收操作。调用System.gc()并不是立即执行垃圾回收,而是向垃圾回收器发送一个请求,告诉它有待回收的对象可以进行回收。 需要注意的是,System.gc()方法的调用并不会立即释放所有内存,也不能保证垃圾回收一定会执行。垃圾回收的具体执行时间是由JVM决定的,而且该方法的执行会造成一定的性能损失。因此,在编写代码时,我们不应该过分依赖于System.gc(),而是应该编写良好的代码结构和逻辑,避免出现内存泄漏等问题。 总之,System.gc()方法是用来手动触发垃圾回收的,它向垃圾回收器发送一个请求,告诉它有待回收的对象可以进行回收。但是需要注意的是,调用System.gc()并不能保证垃圾回收一定会执行,也不能立即释放所有内存,因此在编写代码时应该合理使用,不过度依赖于该方法。 ### 回答3: System.gc()是Java中的一个方法,用于显式地请求垃圾回收器进行垃圾回收。 在Java中,垃圾回收器负责自动回收不再使用的内存,释放掉这些内存供其他程序使用,从而避免了内存泄漏的问题。系统会自动进行垃圾回收,但是我们也可以使用System.gc()方法来主动触发垃圾回收。 当我们调用System.gc()方法时,会向JVM发送一个垃圾回收的请求,但是具体是否立即进行垃圾回收以及回收的效果,取决于JVM的实现。 值得注意的是,尽管我们可以调用System.gc()方法来主动触发垃圾回收,但是这并不意味着每次调用都会导致垃圾回收的立即执行。实际上,JVM会根据自身的策略和算法来决定何时进行垃圾回收,以及要回收多少的内存。 在一般情况下,我们并不需要手动调用System.gc()方法,因为JVM能够根据需要自动进行垃圾回收。只有在某些特殊情况下,比如我们需要尽快回收大量的内存时,可能会使用System.gc()方法来主动触发垃圾回收。 总之,System.gc()方法是Java中一个用于主动触发垃圾回收的方法。但是我们要注意,不要滥用这个方法,因为JVM能够自动进行垃圾回收,并且过多地调用System.gc()方法可能会影响程序的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值