内存堆Gc时公认的根对象

    内存堆的Gc就是回收内存堆中垃圾对象(非active对象),那么这里就有一个问题了,如何寻找垃圾对象?换个思路来解,就是如何找到所有的active的对象,那么剩下的就是垃圾对象了.HotSpot是通过首先找到所谓的根对象,然后根据这些根对象递归或迭代的搜索所有的引用对象,而找到的这些个对象就是所谓的active对象了.其实,Gc时的根对象是一个与运行时上下文相关的概念,以基于内存分代管理的内存代管理器来讲,当对某一个内存代惊进行Minor Gc时,其它内存代中的所有对象都应该被看做是根对象(尽管某些对象可能真的已经是垃圾对象了).本文所要讲的根对象指的是在对内存堆或内存代进行Minor/Full Gc时都认同的“根对象”,这些跟对象主要来源于:Universe相关对象,Java/本地方法栈中的对象等等.

1. Universe相关对象

    Universe模块在JVM中主要负责内存堆的管理这一块,核心就是内存堆管理器的初始化工作.Universe中的根对象主要和JVM内部的Java对象表示模型相关:Klass框架和Oop框架.Klass对象表示的是Java类型的描述信息,Oop对象则是Java实例对象在JVM内存的存在形式.下面简要的介绍常用的几个Klass或Oop对象的内存布局

Klass对象布局


instanceKlass的内存布局

                                                                          

普通java对象的内存布局                                                                                     数组对象的内存布局


   java对象的内存布局中,_metadata表示的是该类型的描述信息对象指针,_mark表示的是该对象运行时状态信息.

1.1 基本类型对应的java.lang.Class对象

oop Universe::_int_mirror                             = NULL;
oop Universe::_float_mirror                           = NULL;
oop Universe::_double_mirror                          = NULL;
oop Universe::_byte_mirror                            = NULL;
oop Universe::_bool_mirror                            = NULL;
oop Universe::_char_mirror                            = NULL;
oop Universe::_long_mirror                            = NULL;
oop Universe::_short_mirror                           = NULL;
oop Universe::_void_mirror                            = NULL;
oop Universe::_mirrors[T_VOID+1]                      = { NULL /*, NULL...*/ };

1.2 基本类型对应的数组类型的描述信息对象

klassOop Universe::_boolArrayKlassObj                 = NULL;
klassOop Universe::_byteArrayKlassObj                 = NULL;
klassOop Universe::_charArrayKlassObj                 = NULL;
klassOop Universe::_intArrayKlassObj                  = NULL;
klassOop Universe::_shortArrayKlassObj                = NULL;
klassOop Universe::_longArrayKlassObj                 = NULL;
klassOop Universe::_singleArrayKlassObj               = NULL;
klassOop Universe::_doubleArrayKlassObj               = NULL;
klassOop Universe::_typeArrayKlassObjs[T_VOID+1]      = { NULL /*, NULL...*/ };

1.3 Java类型相关的描述信息对象

klassOop Universe::_objectArrayKlassObj               = NULL;
klassOop Universe::_methodKlassObj                    = NULL;
klassOop Universe::_constMethodKlassObj               = NULL;
klassOop Universe::_methodDataKlassObj                = NULL;
klassOop Universe::_klassKlassObj                     = NULL;
klassOop Universe::_arrayKlassKlassObj                = NULL;
klassOop Universe::_objArrayKlassKlassObj             = NULL;
klassOop Universe::_typeArrayKlassKlassObj            = NULL;
klassOop Universe::_instanceKlassKlassObj             = NULL;
klassOop Universe::_constantPoolKlassObj              = NULL;
klassOop Universe::_constantPoolCacheKlassObj         = NULL;
klassOop Universe::_compiledICHolderKlassObj          = NULL;
klassOop Universe::_systemObjArrayKlassObj            = NULL;

1.4 常用Java方法描述信息对象

   这里包含了JVM内部频繁使用的3个java方法:java.lang.ref.Finalizer.register()/java.lang.ClassLoader.addClass()/java.lang.reflect.Method.invoke(),先简单的介绍一下这三个java方法的主要用途.

LatestMethodOopCache* Universe::_finalizer_register_cache = NULL;
LatestMethodOopCache* Universe::_loader_addClass_cache    = NULL;
ActiveMethodOopsCache* Universe::_reflect_invoke_cache    = NULL;

    在java.lang.Object里面有一个finalize()的空方法,一旦某个类型实现了这个方法,就会触发JVM的内部行为:该类型对应的实例对象在被Gc之后,JVM就会调用它的finalize(),但并不保证一定会调用.

/**
 * 注册一个实现了finalize()的对象,当gc回收该对象时会掉用它的finalize()
 */
instanceOop instanceKlass::register_finalizer(instanceOop i, TRAPS) {
  if (TraceFinalizerRegistration) {
    tty->print("Registered ");
    i->print_value_on(tty);
    tty->print_cr(" (" INTPTR_FORMAT ") as finalizable", (address)i);
  }
  
  /**
   * 构造调用Java方法所需的参数
   */
  
  instanceHandle h_i(THREAD, i);
  // Pass the handle as argument, JavaCalls::call expects oop as jobjects
  JavaValue result(T_VOID);
  JavaCallArguments args(h_i);
  methodHandle mh (THREAD, Universe::finalizer_register_method());
  
  //调用java.lang.ref.Finalizer.register()方法
  JavaCalls::call(&result, mh, &args, CHECK_NULL);
  return h_i();
}
   java.lang.ClassLoader.addClass()主要用于在jni中加载类的调用.

1.5 内存分配相关的异常实例对象

oop Universe::_out_of_memory_error_java_heap          = NULL;
oop Universe::_out_of_memory_error_perm_gen           = NULL;
oop Universe::_out_of_memory_error_array_size         = NULL;
oop Universe::_out_of_memory_error_gc_overhead_limit  = NULL;
objArrayOop Universe::_preallocated_out_of_memory_error_array = NULL;
oop Universe::_null_ptr_exception_instance            = NULL;
oop Universe::_arithmetic_exception_instance          = NULL;
oop Universe::_virtual_machine_error_instance         = NULL;
oop Universe::_vm_exception                           = NULL;

2. 本地方法创建的全局对象

    JNIHandles中保存了所有Java线程在执行本地方法时申请的全局对象句柄:

JNIHandleBlock* JNIHandles::_global_handles       = NULL;


全局本地对象句柄的视图

/**
 * 为指定的实例对象分配一个句柄
 */
jobject JNIHandleBlock::allocate_handle(oop obj) {
  assert(Universe::heap()->is_in_reserved(obj), "sanity check");

  if (_top == 0) {
    // This is the first allocation or the initial block got zapped when
    // entering a native function. If we have any following blocks they are
    // not valid anymore.
    for (JNIHandleBlock* current = _next; current != NULL;
         current = current->_next) {
      assert(current->_last == NULL, "only first block should have _last set");
      assert(current->_free_list == NULL,
             "only first block should have _free_list set");
      current->_top = 0;
      if (ZapJNIHandleArea) current->zap();
    }

    // Clear initial block
    _free_list = NULL;
    _allocate_before_rebuild = 0;
    _last = this;
    if (ZapJNIHandleArea) zap();
  }

  //最后一个块有空闲句柄
  if (_last->_top < block_size_in_oops) {
    oop* handle = &(_last->_handles)[_last->_top++];
    *handle = obj;
    return (jobject) handle;
  }

  // Try free list
  if (_free_list != NULL) {
    oop* handle = _free_list;
    _free_list = (oop*) *_free_list;
    *handle = obj;
    return (jobject) handle;
  }

  // Check if unused block follow last
  if (_last->_next != NULL) {
    // update last and retry
    _last = _last->_next;
    return allocate_handle(obj);
  }

  // No space available, we have to rebuild free list or expand
  if (_allocate_before_rebuild == 0) {
      rebuild_free_list();        // updates _allocate_before_rebuild counter

  } else {	//分配一个新的句柄存储块

    // Append new block
    Thread* thread = Thread::current();
    Handle obj_handle(thread, obj);

    // This can block, so we need to preserve obj accross call.
    _last->_next = JNIHandleBlock::allocate_block(thread);
    _last = _last->_next;
    _allocate_before_rebuild--;
    obj = obj_handle();
  }

  return allocate_handle(obj);  // retry
}

void JNIHandleBlock::oops_do(OopClosure* f) {
  JNIHandleBlock* current_chain = this;
  // Iterate over chain of blocks, followed by chains linked through the
  // pop frame links.
  while (current_chain != NULL) {
    for (JNIHandleBlock* current = current_chain; current != NULL;
         current = current->_next) {
      assert(current == current_chain || current->pop_frame_link() == NULL,
        "only blocks first in chain should have pop frame link set");
      for (int index = 0; index < current->_top; index++) {
        oop* root = &(current->_handles)[index];
        oop value = *root;
        // traverse heap pointers only, not deleted handles or free list
        // pointers
        if (value != NULL && Universe::heap()->is_in_reserved(value)) {
          f->do_oop(root);
        }
      }
      // the next handle block is valid only if current block is full
      if (current->_top < block_size_in_oops) {
        break;
      }
    }
    current_chain = current_chain->pop_frame_link();

  }//while

}

/**
 * 遍历所有的全局本地对象
 */
void JNIHandles::oops_do(OopClosure* f) {
  f->do_oop(&_deleted_handle);
  _global_handles->oops_do(f);
}

3. 方法栈中的对象

    这里主要指的是每一个Java线程在执行过程中创建的私有局部变量,分为两块:一是在执行Java方法时创建的,二是在执行本地方法时创建的.

void Threads::oops_do(OopClosure* f, CodeBlobClosure* cf) {
  ALL_JAVA_THREADS(p) {
    p->oops_do(f, cf);
  }

  VMThread::vm_thread()->oops_do(f, cf);
}

void Thread::oops_do(OopClosure* f, CodeBlobClosure* cf) {

  active_handles()->oops_do(f);	//本地局部对象

  // Do oop for ThreadShadow
  f->do_oop((oop*)&_pending_exception);	//当前线程可能已经抛出的异常对象

  handle_area()->oops_do(f);	//局部对象
}

1.Java方法栈中的对象

  每一个Java线程都私有一个句柄区_handle_area来存储其运行过程中创建的临时对象,这个句柄区是随着Java线程的栈帧变化的,这个句柄区的数据结构如下


    Java线程每调用一个Java方法就会创建一个对应HandleMark来保存此时Java线程分配对象句柄的上下文环境,然后等调用返回后即行恢复:

void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArguments* args, TRAPS) {
     ...

     {
      HandleMark hm(thread);  // HandleMark used by HandleMarkCleaner

      printf("%s[%d] [tid: %lu]: 开始执行方法[%s]...\n", __FILE__, __LINE__, pthread_self(), method->name()->as_C_string());
      StubRoutines::call_stub()(
        (address)&link,
        // (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
        result_val_address,          // see NOTE above (compiler problem)
        result_type,
        method(),
        entry_point,
        args->parameters(),
        args->size_of_parameters(),
        CHECK
      );

      result = link.result();  // circumvent MS C++ 5.0 compiler bug (result is clobbered across call)
      // Preserve oop return value across possible gc points
      if (oop_result_flag) {
        thread->set_vm_result((oop) result->get_jobject());
      }

    }

    ...
}

void HandleMark::initialize(Thread* thread) {
  _thread = thread;

  //保存当前线程分配对象句柄的地址
  _area  = thread->handle_area();
  // Save current top
  _chunk = _area->_chunk;
  _hwm   = _area->_hwm;
  _max   = _area->_max;

  NOT_PRODUCT(_size_in_bytes = _area->_size_in_bytes;)
  debug_only(_area->_handle_mark_nesting++);
  assert(_area->_handle_mark_nesting > 0, "must stack allocate HandleMarks");
  debug_only(Atomic::inc(&_nof_handlemarks);)

  // Link this in the thread
  set_previous_handle_mark(thread->last_handle_mark());
  thread->set_last_handle_mark(this);
}


HandleMark::~HandleMark() {
  HandleArea* area = _area;   // help compilers with poor alias analysis

  assert(area == _thread->handle_area(), "sanity check");
  assert(area->_handle_mark_nesting > 0, "must stack allocate HandleMarks" );
  debug_only(area->_handle_mark_nesting--);

  // Debug code to trace the number of handles allocated per mark/
#ifdef ASSERT
  if (TraceHandleAllocation) {
    size_t handles = 0;
    Chunk *c = _chunk->next();
    if (c == NULL) {
      handles = area->_hwm - _hwm; // no new chunk allocated
    } else {
      handles = _max - _hwm;      // add rest in first chunk
      while(c != NULL) {
        handles += c->length();
        c = c->next();
      }
      handles -= area->_max - area->_hwm; // adjust for last trunk not full
    }
    handles /= sizeof(void *); // Adjust for size of a handle
    if (handles > HandleAllocationLimit) {
      // Note: _nof_handlemarks is only set in debug mode
      warning("%d: Allocated in HandleMark : %d", _nof_handlemarks, handles);
    }
  }
#endif

  // Delete later chunks
  if( _chunk->next() ) {
    _chunk->next_chop();
  }
  
  // 恢复之前线程分配对象句柄的地址
  area->_chunk = _chunk;
  area->_hwm = _hwm;
  area->_max = _max;
  NOT_PRODUCT(area->set_size_in_bytes(_size_in_bytes);)

#ifdef ASSERT
  // clear out first chunk (to detect allocation bugs)
  if (ZapVMHandleArea) {
    memset(_hwm, badHandleValue, _max - _hwm);
  }
  Atomic::dec(&_nof_handlemarks);
#endif

  // Unlink this from the thread
  _thread->set_last_handle_mark(previous_handle_mark());
}


2.本地方法栈中的对象

    Java线程使用一个对象句柄存储块JNIHandleBlock来为其于在本地方法中申请的临时对象创建对应的句柄,JNIHandleBlock中有一个_pop_frame_link属性,被用来保存Java线程切换方法时分配本地对象句柄的上下文环境.


4. 对象同步监视器中的对象

  对于每一个被synchronized的Java对象,JVM会在内部为其创建一个对应的对象监视器ObjectMonitor,用来控制与其相关的线程:

void ObjectSynchronizer::oops_do(OopClosure* f) {
  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
  for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) {
    assert(block->object() == CHAINMARKER, "must be a block header");
    for (int i = 1; i < _BLOCKSIZE; i++) {
      ObjectMonitor* mid = &block[i];
      if (mid->object() != NULL) {
        f->do_oop((oop*)mid->object_addr());
      }
    }
  }
}

5. Java级管理接口(Management)中的对象

    Management中的根对象主要是关于JVM中的线程/内存/Gc的统计,监控等相关的类型描述信息或对象:

void Management::oops_do(OopClosure* f) {
  MemoryService::oops_do(f);
  ThreadService::oops_do(f);

  f->do_oop((oop*) &_sensor_klass);
  f->do_oop((oop*) &_threadInfo_klass);
  f->do_oop((oop*) &_memoryUsage_klass);
  f->do_oop((oop*) &_memoryPoolMXBean_klass);
  f->do_oop((oop*) &_memoryManagerMXBean_klass);
  f->do_oop((oop*) &_garbageCollectorMXBean_klass);
  f->do_oop((oop*) &_managementFactory_klass);
  f->do_oop((oop*) &_garbageCollectorImpl_klass);
  f->do_oop((oop*) &_gcInfo_klass);
}

6. 虚拟机工具接口(JVMTI)中的对象

     关于Java虚拟机工具接口中的根对象,本文不详细介绍

7. 系统字典(SystemDictionary)中的对象

    SystemDictionary中的根对象主要包括各种基础类型的描述信息:

java.lang.Object
java.lang.String
java.lang.Class
java.lang.Cloneable
java.lang.ClassLoader
java.io.Serializable
java.lang.System
java.lang.Throwable
java.lang.Error
java.lang.ThreadDeath
java.lang.Exception
java.lang.RuntimeException
java.security.ProtectionDomain
java.security.AccessControlContext
java.lang.ClassNotFoundException
java.lang.NoClassDefFoundError
java.lang.LinkageError
java.lang.ClassCastException
java.lang.ArrayStoreException
java.lang.VirtualMachineError
java.lang.OutOfMemoryError
java.lang.StackOverflowError
java.lang.IllegalMonitorStateException

java.lang.ref.Reference   
java.lang.ref.SoftReference
java.lang.ref.WeakReference
java.lang.ref.FinalReference
java.lang.ref.PhantomReference 

java.lang.ref.Finalizer
java.lang.Thread  
java.lang.ThreadGroup
java.util.Properties 
java.lang.reflect.AccessibleObject
java.lang.reflect.Field
java.lang.reflect.Method 
java.lang.reflect.Constructor

sun.reflect.MagicAccessorImpl
sun.reflect.MethodAccessorImpl
sun.reflect.ConstructorAccessorImpl  
sun.reflect.DelegatingClassLoader
sun.reflect.ConstantPool
sun.reflect.UnsafeStaticFieldAccessorImpl
java.lang.invoke.MethodHandle  
java.lang.invoke.MemberName          
java.lang.invoke.MethodHandleNatives  
java.lang.invoke.AdapterMethodHandle   
java.lang.invoke.BoundMethodHandle   
java.lang.invoke.DirectMethodHandle    
java.lang.invoke.MethodType            
java.lang.invoke.MethodTypeForm     
java.lang.BootstrapMethodError      
java.lang.invoke.WrongMethodTypeException
java.lang.invoke.CallSite          
java.lang.invoke.CountingMethodHandle
java.lang.invoke.ConstantCallSite     
java.lang.invoke.MutableCallSite  
java.lang.invoke.VolatileCallSite

java.lang.StringBuffer 
java.lang.StringBuilder  
java.nio.Buffer
 
sun.misc.AtomicLongCSImpl
sun.jkernel.DownloadManager
sun.misc.PostVMInitHook

java.lang.Boolean    
java.lang.Character 
java.lang.Float       
java.lang.Double 
java.lang.Byte        
java.lang.Short    
java.lang.Integer
java.lang.Long 

8. 字符串常量表(StringTable)中的对象

   顾名思义,字符串常量表中存储的主要是常量字符串,特别是类型的全限定名,方法的签名等对应的字符串.

9. 代码高速缓存区中的对象

    代码高速缓存区CodeCache中主要存储的Java方法被本地编译之后对应的代码片段.

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值