Hotspot 内存管理之ClassLoaderData 源码解析

   目录

一、ClassLoaderData

1、Dependencies

2、ChunkedHandleList

3、JNIMethodBlock

4、init_null_class_loader_data / init_dependencies

 5、构造和析构函数

6、record_dependency

7、add_to_deallocate_list /free_deallocate_list

8、metaspace_non_null

9、add_class / remove_class

二、ClassLoaderDataGraph

1、定义

 2、find_or_create

3、purge

4、do_unloading


在《Hotspot 内存管理之Metaspace(三) 源码解析》中讲解了Metaspace的初始化和内存管理等接口,总结了Metaspace相关底层类的数据结构和调用关系,本篇博客讲解跟Metaspace直接相关的负责初始化Metaspace实例的ClassLoaderData的相关类的实现。

一、ClassLoaderData

       ClassLoaderData负责初始化并销毁一个ClassLoader实例对应的Metaspace,是GC的根节点,提供引用遍历的迭代器。ClassLoaderData的定义在hotspot src/share/vm/classfile/classLoaderData.hpp中,包含的属性如下:

  • static ClassLoaderData * _the_null_class_loader_data; //启动类加载器对应的ClassLoaderData
  • oop _class_loader;//关联的Java ClassLoader实例
  • Dependencies _dependencies;// 依赖
  • Metaspace * _metaspace; //该ClassLoader为加载的Klass分配内存的Metaspace
  • Mutex* _metaspace_lock; //分配内存的锁
  •  bool _unloading;//为true,表示被卸载了
  • bool _keep_alive;// 为true,表示ClassLoaderData是活跃的但是没有关联的活跃对象,比如匿名类的类加载器和启动类加载器实例,为true则不能被GC回收掉
  • bool _is_anonymous;//为true,表示ClassLoaderData主要加载匿名类
  • volatile int _claimed; //用来标记该ClassLoaderData已经被遍历过了
  • Klass* _klasses;  //该ClassLoaderData加载的所有Klass
  • ChunkedHandleList _handles; //保存所有常量池的引用
  • JNIMethodBlock*      _jmethod_ids;
  • GrowableArray*      _deallocate_list;//需要被释放的从Metaspace 中分配的内存
  • ClassLoaderData* _next; //下一个ClassLoaderData
  • static Metaspace* _ro_metaspace;  //启动类加载器使用的只读的Metaspace,DumpSharedSpaces为true时使用
  •  static Metaspace* _rw_metaspace; // 启动类加载器使用的可读写的Metaspace,DumpSharedSpaces为true时使用

1、Dependencies

     Dependencies是ClassLoaderData的内部类,表示引用此ClassLoaderDat的对象,特殊场景下使用,这些引用对象无法通过GC遍历到,其定义如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第1张图片

其init和add方法的源码实现如下:

void ClassLoaderData::Dependencies::init(TRAPS) {
  //创建一个长度为2的Ojbect数组
  _list_head = oopFactory::new_objectArray(2, CHECK);
}

void ClassLoaderData::Dependencies::add(Handle dependency, TRAPS) {
  objArrayOop ok = _list_head;
  objArrayOop last = NULL;
  //不断遍历,如果已经在列表中则返回
  while (ok != NULL) {
    last = ok;
    //第一个元素是obj
    if (ok->obj_at(0) == dependency()) {
      // Don't need to add it
      return;
    }
    //第二个元素是一个obj数组
    ok = (objArrayOop)ok->obj_at(1);
  }

  //last不能为空
  assert (last != NULL, "dependencies should be initialized");
  objArrayHandle last_handle(THREAD, last);

  //创建一个新的数组,将目标dependency放到索引为0的位置
  objArrayOop deps = oopFactory::new_objectArray(2, CHECK);
  deps->obj_at_put(0, dependency());

  // Must handle over GC points
  objArrayHandle new_dependency(THREAD, deps);
  locked_add(last_handle, new_dependency, THREAD);
}

void ClassLoaderData::Dependencies::locked_add(objArrayHandle last_handle,
                                               objArrayHandle new_dependency,
                                               Thread* THREAD) {

  //获取对象锁,从而安全的添加新的依赖Obj
  ObjectLocker ol(Handle(THREAD, _list_head), THREAD);

  oop loader_or_mirror = new_dependency->obj_at(0);

  // Since the dependencies are only added, add to the end.
  objArrayOop end = last_handle();
  objArrayOop last = NULL;
  while (end != NULL) {
    last = end;
    //再检查一遍,可能其他线程已经完成添加了
    if (end->obj_at(0) == loader_or_mirror) {
      // Don't need to add it
      return;
    }
    end = (objArrayOop)end->obj_at(1);
  }
  assert (last != NULL, "dependencies should be initialized");
  //如果last本身是一个空数组则添加到索引为0的位置,否则放到索引为1的位置
  if (last->obj_at(0) == NULL) {
    last->obj_at_put(0, new_dependency->obj_at(0));
  } else {
    last->obj_at_put(1, new_dependency());
  }
}

_list_head属性是一个长度为2的Obj数组,第一个元素是依赖的Obj,第二个元素是下一个依赖的obj数组的引用,下一个依赖的obj数组同样是2个元素的obj数组,如此便构成了一个依赖的obj的链表。添加的时候首先判断目标obj是否在链表中,如果不在则添加到末尾,添加的时候需要获取_list_head属性的对象锁。其中add方法的调用链如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第2张图片

2、ChunkedHandleList

     ChunkedHandleList也是ClassLoaderData的内部类,其定义如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第3张图片

一个Chunk实际就是一个固定容量的oop数组,size表示该数组已使用的元素个数,next表示上一个已经被占满的Chunk。上述析构方法和add方法的实现如下:

ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
  Chunk* c = _head;
  while (c != NULL) {
    Chunk* next = c->_next;
    delete c;
    c = next;
  }
}

oop* ClassLoaderData::ChunkedHandleList::add(oop o) {
  //_head为NULL或者已满,则创建一个新的Chunk
  if (_head == NULL || _head->_size == Chunk::CAPACITY) {
    Chunk* next = new Chunk(_head);
    //原子的更新_head属性,将新创建的next作为_head
    OrderAccess::release_store_ptr(&_head, next);
  }
  //保存oop
  oop* handle = &_head->_data[_head->_size];
  *handle = o;
  //增加size
  OrderAccess::release_store(&_head->_size, _head->_size + 1);
  return handle;
}

其中add方法的调用链如下: 

 Hotspot 内存管理之ClassLoaderData 源码解析_第4张图片

3、JNIMethodBlock

     JNIMethodBlock用来生成jmethodID的,每个jmethodID实际是一个Method**。JNIMethodBlock的定义如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第5张图片

其结构跟ChunkedHandleList的Chunk类似,top属性表示已经被分配的数组元素个数,next表示下一个可以分配的JNIMethodBlock,其add_method方法的实现如下:

 Method** add_method(Method* m) {
    //如果未分配完
    if (_top < number_of_methods) {
      // top points to the next free entry.
      int i = _top;
      _methods[i] = m;
      _top++;
      return &_methods[i];
    } else if (_top == number_of_methods) {
      //如果已分配完,判断是否存在空闲的元素
      for (int i = 0; i< number_of_methods; i++) {
        if (_methods[i] == _free_method) {
          //使用空闲的元素分配
          _methods[i] = m;
          return &_methods[i];
        }
      }
      _top++;
    }
    //没有空闲的,需要分配一个新的JNIMethodBlock
    if (_next == NULL) {
      _next = new JNIMethodBlock();
    }
    //使用next添加新的Method
    return _next->add_method(m);
  }

 ClassLoaderData中设置_jmethod_ids属性的只有一个方法,set_jmethod_ids,该方法的调用链如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第6张图片

make_jmethod_id方法的实现如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第7张图片

生成的jmethodID实际就是add_method方法返回的Method**。 

4、init_null_class_loader_data / init_dependencies

     这两个方法都是用来初始化启动类加载器对应的_the_null_class_loader_data属性,都是在Universe初始化的时候调用的,其调用链如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第8张图片

两方法的源码如下:

static void init_null_class_loader_data() {
    assert(_the_null_class_loader_data == NULL, "cannot initialize twice");
    assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice");

    //初始化_the_null_class_loader_data
    _the_null_class_loader_data = new ClassLoaderData((oop)NULL, false, Dependencies());
    ClassLoaderDataGraph::_head = _the_null_class_loader_data;
    assert(_the_null_class_loader_data->is_the_null_class_loader_data(), "Must be");
 //DumpSharedSpaces默认为false    
if (DumpSharedSpaces) {
      _the_null_class_loader_data->initialize_shared_metaspaces();
    }
  }

bool is_the_null_class_loader_data() const {
    return this == _the_null_class_loader_data;
  }

void ClassLoaderData::initialize_shared_metaspaces() {
  assert(DumpSharedSpaces, "only use this for dumping shared spaces");
  assert(this == ClassLoaderData::the_null_class_loader_data(),
         "only supported for null loader data for now");
  assert (!_shared_metaspaces_initialized, "only initialize once");
  MutexLockerEx ml(metaspace_lock(),  Mutex::_no_safepoint_check_flag);
  _ro_metaspace = new Metaspace(_metaspace_lock, Metaspace::ROMetaspaceType);
  _rw_metaspace = new Metaspace(_metaspace_lock, Metaspace::ReadWriteMetaspaceType);
  _shared_metaspaces_initialized = true;
}

void ClassLoaderData::init_dependencies(TRAPS) {
  assert(!Universe::is_fully_initialized(), "should only be called when initializing");
  assert(is_the_null_class_loader_data(), "should only call this for the null class loader");
  _dependencies.init(CHECK);
}

 5、构造和析构函数

两方法的源码如下:

ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) :
  _class_loader(h_class_loader()),
  _is_anonymous(is_anonymous),
  _keep_alive(is_anonymous || h_class_loader.is_null()),
  _metaspace(NULL), _unloading(false), _klasses(NULL),
  _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
  _next(NULL), _dependencies(dependencies),
  _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
    // empty
}

ClassLoaderData::~ClassLoaderData() {
  //遍历该ClassLoader加载的所有Klass,执行release_C_heap_structures方法
  classes_do(InstanceKlass::release_C_heap_structures);

  Metaspace *m = _metaspace;
  if (m != NULL) {
    _metaspace = NULL;
    //释放Metaspace
    delete m;
  }

  if (_jmethod_ids != NULL) {
    //释放_jmethod_ids
    Method::clear_jmethod_ids(this);
  }
  //删除 lock
  delete _metaspace_lock;

  if (_deallocate_list != NULL) {
    delete _deallocate_list;
  }
}

void ClassLoaderData::classes_do(void f(InstanceKlass*)) {
  //遍历所有加载的类
  for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
    if (k->oop_is_instance()) {
      f(InstanceKlass::cast(k));
    }
    assert(k != k->next_link(), "no loops!");
  }
}

重点关注其调用链,如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第9张图片

Hotspot 内存管理之ClassLoaderData 源码解析_第10张图片

6、record_dependency

     record_dependency用于记录引用了当前ClassLoaderData的Klass,这些Klass不能通过正常的GC遍历方式找到,源码实现如下:

void ClassLoaderData::record_dependency(Klass* k, TRAPS) {
  ClassLoaderData * const from_cld = this;
  ClassLoaderData * const to_cld = k->class_loader_data();

  // 启动类加载器不会被销毁,所以不需要记录引用该加载器的Klass
  if (to_cld->is_the_null_class_loader_data()) {
    return;
  }

  oop to;
  if (to_cld->is_anonymous()) {
    // Anonymous class dependencies are through the mirror.
    to = k->java_mirror();
  } else {
    to = to_cld->class_loader();

   //非匿名类加载器下,如果当前类加载器是目标类的类加载器的父类加载器,则不需要添加
    if (!from_cld->is_anonymous()) {
      // Check that this dependency isn't from the same or parent class_loader
      oop from = from_cld->class_loader();

      oop curr = from;
      while (curr != NULL) {
        if (curr == to) {
          return; 
        }
        curr = java_lang_ClassLoader::parent(curr);
      }
    }
  }

  //这种引用关系不能用过正常的GC遍历到,所以通过dependency的方式单独保存
  Handle dependency(THREAD, to);
  from_cld->_dependencies.add(dependency, CHECK);
}

保存下来的_dependencies主要是为了GC遍历使用,参考ClassLoaderData::oops_do方法的实现,如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第11张图片

该方法的调用链如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第12张图片

7、add_to_deallocate_list /free_deallocate_list

     add_to_deallocate_list用于临时保存需要被释放的Klass,Method等元数据的指针,因为这些元数据可能依然被使用,所以不能立即释放,只能等到类加载器被卸载了才释放。free_deallocate_list是类加载器被卸载时调用来释放deallocate_list中的元数据,这两方法的调用链如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第13张图片

Hotspot 内存管理之ClassLoaderData 源码解析_第14张图片

这两方法的源码如下:

// Add this metadata pointer to be freed when it's safe.  This is only during
// class unloading because Handles might point to this metadata field.
void ClassLoaderData::add_to_deallocate_list(Metadata* m) {
  // 共享的元数据不能被删除
  if (!m->is_shared()) {
    //获取锁
    MutexLockerEx ml(metaspace_lock(),  Mutex::_no_safepoint_check_flag);
    if (_deallocate_list == NULL) {
      //初始化_deallocate_list
      _deallocate_list = new (ResourceObj::C_HEAP, mtClass) GrowableArray(100, true);
    }
    //添加到列表中
    _deallocate_list->append_if_missing(m);
  }
}

// Deallocate free metadata on the free list.  How useful the PermGen was!
void ClassLoaderData::free_deallocate_list() {
  //该方法只能在安全点的时候调用
  assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
  if (_deallocate_list == NULL) {
    return;
  }
  // Go backwards because this removes entries that are freed.
  for (int i = _deallocate_list->length() - 1; i >= 0; i--) {
    Metadata* m = _deallocate_list->at(i);
    //Metadata不在栈上,即不再被使用
    if (!m->on_stack()) {
      //从链表中移除
      _deallocate_list->remove_at(i);
      //根据Metadata的类型分别释放
      if (m->is_method()) {
        MetadataFactory::free_metadata(this, (Method*)m);
      } else if (m->is_constantPool()) {
        MetadataFactory::free_metadata(this, (ConstantPool*)m);
      } else if (m->is_klass()) {
        MetadataFactory::free_metadata(this, (InstanceKlass*)m);
      } else {
        ShouldNotReachHere();
      }
    }
  }
}

free_metadata是一个模板方法,该方法的实现如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第15张图片

deallocate_contents方法完成md内部相关数据结构的清理,deallocate方法用于释放其对应的内存。

8、metaspace_non_null

     metaspace_non_null方法用于返回ClassLoaderData的_metaspace属性,如果未初始化则会完成该属性初始化。其源码实现如下:

Metaspace* ClassLoaderData::metaspace_non_null() {
  assert(!DumpSharedSpaces, "wrong metaspace!");
  //延迟初始化,因为部分ClassLoader并不会加载类,也就不需要从Metaspace分配空间
  if (_metaspace == NULL) {
    //获取锁metaspace_lock
    MutexLockerEx ml(metaspace_lock(),  Mutex::_no_safepoint_check_flag);
    //重新检查,可能其他线程已经完成初始化
    if (_metaspace != NULL) {
      return _metaspace;
    }
    //如果是启动类加载器
    if (this == the_null_class_loader_data()) {
      assert (class_loader() == NULL, "Must be");
      set_metaspace(new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType));
    } else if (is_anonymous()) {//如果是匿名类类加载器
      if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
        tty->print_cr("is_anonymous: %s", class_loader()->klass()->internal_name());
      }
      set_metaspace(new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType));
    } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
      //如果是sun_reflect_DelegatingClassLoader类加载器
      if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
        tty->print_cr("is_reflection: %s", class_loader()->klass()->internal_name());
      }
      set_metaspace(new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType));
    } else {
      //如果是普通的类加载器
      set_metaspace(new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType));
    }
  }
  return _metaspace;
}

9、add_class / remove_class

      add_class用于将已经完成类加载的类对应的Klass加入到ClassLoaderData管理的Klass链表中,remove_class用于类卸载的时候将Klass从ClassLoaderData管理的Klass链表中移除,这两方法的调用链如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第16张图片

 

InstanceKlass::deallocate_contents就是上一节free_deallocate_list方法释放Klass对应内存时调用的方法。这两方法的源码如下:

void ClassLoaderData::add_class(Klass* k) {
  MutexLockerEx ml(metaspace_lock(),  Mutex::_no_safepoint_check_flag);
  //加入到链表的头部
  Klass* old_value = _klasses;
  k->set_next_link(old_value);
  // link the new item into the list
  _klasses = k;

  if (TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
    ResourceMark rm;
    //打印日志
    tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
                  PTR_FORMAT " loader: " PTR_FORMAT " %s",
                  p2i(k),
                  k->external_name(),
                  p2i(k->class_loader_data()),
                  p2i((void *)k->class_loader()),
                  loader_name());
  }
}


void ClassLoaderData::remove_class(Klass* scratch_class) {
  MutexLockerEx ml(metaspace_lock(),  Mutex::_no_safepoint_check_flag);
  Klass* prev = NULL;
  //遍历所有的Klass,找到待删除的Klass,然后从链表中移除
  for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
    if (k == scratch_class) {
      if (prev == NULL) {
        //待删除的类位于链表头部
        _klasses = k->next_link();
      } else {
        //待删除的类位于链表中间
        Klass* next = k->next_link();
        prev->set_next_link(next);
      }
      return;
    }
    prev = k;
    assert(k != k->next_link(), "no loops!");
  }
  ShouldNotReachHere();   // should have found this class!!
}

二、ClassLoaderDataGraph

1、定义

    ClassLoaderDataGraph的定义同样位于classLoaderData.hpp中,相当于ClassLoaderData的一个管理类,方便遍历所有的ClassLoaderData,其定义的属性和方法都是静态的,属性如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第17张图片

其中head表示当前活跃的ClassLoaderData链表,unloading表示即将被卸载的ClassLoaderData链表,通过do_unloading方法将某个不再活跃的ClassLoaderData加入到unloading链表中,最终由purge方法触发unloading链表中所有ClassLoaderData的内存释放。定义的方法主要是GC遍历相关的,如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第18张图片

其实现都是通过_head属性遍历所有的ClassLoaderData然后调用ClassLoaderData的对应遍历方法,重点关注以下方法的实现。

 2、find_or_create

       find_or_create用于查找某个java/lang/ClassLoader实例对应的ClassLoaderData,如果不存在则为该实例创建一个新的ClassLoaderData实例并添加到ClassLoaderDataGraph管理的ClassLoaderData链表中。注意ClassLoaderData指针的保存位置比较特殊,不是在ClassLoader实例的内存中,而是内存外,内存上方的8字节处,为什么这8字节在没有保存ClassLoaderData指针时是NULL了?因为Java对象创建的时候会保证对象间有8字节的空隙。该方法实现的源码如下:

inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader, TRAPS) {
  //校验loader必须是一个oop
  guarantee(loader() != NULL && loader()->is_oop(), "Loader must be oop");
  //根据java/lang/ClassLoader对象的地址获取ClassLoaderData的指针,如果不为空说明这个ClassLoader对象
  //已经添加到ClassLoaderDataGraph中了,否则需要添加
  ClassLoaderData* loader_data= java_lang_ClassLoader::loader_data(loader());
  if (loader_data) {
     return loader_data;
  }
  return ClassLoaderDataGraph::add(loader, false, THREAD);
}

//创建一个新的ClassLoaderData实例,然后将其作为java/lang/ClassLoader的隐藏属性保存在ClassLoader实例中
ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRAPS) {
  ClassLoaderData::Dependencies dependencies(CHECK_NULL);
  //通过No_Safepoint_Verifier的构造方法校验当前不在安全点上,没有进行GC
  No_Safepoint_Verifier no_safepoints; 

  ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous, dependencies);

  //如果不是匿名类
  if (!is_anonymous) {
    //获取相对ClassLoader地址偏移为-1的地址,即在ClassLoader实例内存上方的8字节
    ClassLoaderData** cld_addr = java_lang_ClassLoader::loader_data_addr(loader());
    //将ClassLoaderData的地址原子的保存进去
    ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
    if (old != NULL) {
      //不等于NULL说明有其他线程完成了保存动作,因此将创建的ClassLoaderData释放掉,返回其他线程已经保存的ClassLoaderData
      delete cld;
      return old;
    }
  }

  //设置成功,将新创建的ClassLoaderData加入到链表中
  ClassLoaderData** list_head = &_head;
  ClassLoaderData* next = _head;

  do {
    cld->set_next(next);
    //原子的修改链表头,如果因为并发修改失败则不断重试
    ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
    if (exchanged == next) {
      //修改成功
      if (TraceClassLoaderData) {
        //打印日志
        ResourceMark rm;
        tty->print("[ClassLoaderData: ");
        tty->print("create class loader data " INTPTR_FORMAT, p2i(cld));
        tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()),
                   cld->loader_name());
        tty->print_cr("]");
      }
      return cld;
    }
    //链表头被其他线程修改了,重置next
    next = exchanged;
  } while (true);

}

该方法的调用链如下:

3、purge

     purge方法用于释放需要被卸载掉的ClassLoaderData,该方法的调用链如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第19张图片

该方法的源码如下:

void ClassLoaderDataGraph::purge() {
  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
  ClassLoaderData* list = _unloading;
  _unloading = NULL;
  ClassLoaderData* next = list;
  //遍历待释放的ClassLoaderData列表
  while (next != NULL) {
    ClassLoaderData* purge_me = next;
    next = purge_me->next();
    //删除ClassLoaderData,调用其析构方法
    delete purge_me;
  }
  //释放Metaspace中所有空闲的VirtualSpaceNode
  Metaspace::purge();
}

4、do_unloading

     do_unloading用于遍历所有的活跃ClassLoaderData,判断其是否活跃,如果不再活跃则将其从活跃链表中移除,加入到不活跃的ClassLoaderData链表中,并通知该ClassLoaderData加载的所有Klass类加载器被卸载。该方法的调用链如下:

Hotspot 内存管理之ClassLoaderData 源码解析_第20张图片

该方法的源码如下: 

// Move class loader data from main list to the unloaded list for unloading
// and deallocation later.
bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, bool clean_alive) {
  ClassLoaderData* data = _head;
  ClassLoaderData* prev = NULL;
  //seen_dead_loader表示找到了需要卸载的ClassLoaderData
  bool seen_dead_loader = false;

  _saved_unloading = _unloading;
  //从_head开始遍历
  while (data != NULL) {
    //如果是活跃的,不能被GC回收,则跳到下一个
    if (data->is_alive(is_alive_closure)) {
      prev = data;
      data = data->next();
      continue;
    }
    //需要被垃圾回收
    seen_dead_loader = true;
    ClassLoaderData* dead = data;
    //执行ClassLoaderData卸载
    dead->unload();
    //将其从活跃链表中移除
    data = data->next();
    if (prev != NULL) {
      prev->set_next(data);
    } else {
      assert(dead == _head, "sanity check");
      _head = data;
    }
    //将其加入到待卸载链表中
    dead->set_next(_unloading);
    _unloading = dead;
  }

  if (clean_alive) {
    //清理之前版本的Klass和ClassLoaderData的_deallocate_list
    ClassLoaderDataGraph::clean_metaspaces();
  }

  if (seen_dead_loader) {
    //遍历所有_unloading中的ClassLoaderData,发布类卸载事件
    post_class_unload_events();
  }

  return seen_dead_loader;
}

bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
  bool alive = keep_alive() //启动类加载器和未使用完的匿名类类加载器的ClassLoaderData的keep_alive返回true
      || is_alive_closure->do_object_b(keep_alive_object());

  return alive;
}

void ClassLoaderData::unload() {
  _unloading = true;

  //遍历所有加载的Klass,通知即将被卸载
  classes_do(InstanceKlass::notify_unload_class);

  if (TraceClassLoaderData) {
    //打印日志
    ResourceMark rm;
    tty->print("[ClassLoaderData: unload loader data " INTPTR_FORMAT, p2i(this));
    tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()),
               loader_name());
    if (is_anonymous()) {
      tty->print(" for anonymous class  " INTPTR_FORMAT " ", p2i(_klasses));
    }
    tty->print_cr("]");
  }
}

void ClassLoaderDataGraph::clean_metaspaces() {
  // mark metadata seen on the stack and code cache so we can delete unneeded entries.
  bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
  MetadataOnStackMark md_on_stack(has_redefined_a_class);

  if (has_redefined_a_class) {
    // 发生了类的重定义,通知所有已加载的Klass清理之前版本的Klass的常量池和弱方法引用等
    for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
      data->classes_do(InstanceKlass::purge_previous_versions);
    }
  }

  //遍历所有的ClassLoaderData释放_deallocate_list保存的待释放内存
  free_deallocate_lists();
}

void ClassLoaderDataGraph::free_deallocate_lists() {
  for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
    // We need to keep this data until InstanceKlass::purge_previous_version has been
    // called on all alive classes. See the comment in ClassLoaderDataGraph::clean_metaspaces.
    cld->free_deallocate_list();
  }

  // In some rare cases items added to the unloading list will not be freed elsewhere.
  // To keep it simple, walk the _unloading list also.
  for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
    cld->free_deallocate_list();
  }
}

void ClassLoaderDataGraph::post_class_unload_events(void) {
#if INCLUDE_TRACE
  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
  if (Tracing::enabled()) {
    if (Tracing::is_event_enabled(TraceClassUnloadEvent)) {
      assert(_unloading != NULL, "need class loader data unload list!");
      _class_unload_time = Ticks::now();
      //遍历_unloading中的所有ClassLoaderData的Klass,执行class_unload_event方法,发布EventClassUnload事件
      classes_unloading_do(&class_unload_event);
    }
    Tracing::on_unloading_classes();
  }
#endif
}

void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) {
  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
  // Only walk the head until any clds not purged from prior unloading
  // (CMS doesn't purge right away).
  for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
    cld->classes_do(f);
  }
}

void ClassLoaderDataGraph::class_unload_event(Klass* const k) {

  // post class unload event
  EventClassUnload event(UNTIMED);
  event.set_endtime(_class_unload_time);
  event.set_unloadedClass(k);
  oop defining_class_loader = k->class_loader();
  event.set_definingClassLoader(defining_class_loader != NULL ?
                                defining_class_loader->klass() : (Klass*)NULL);
  event.commit();
}

 

你可能感兴趣的:(Hotspot和Linux内核,ClassLoaderData,JNIMethodBlock,Dependencies)