目錄
4、init_null_class_loader_data / init_dependencies
7、add_to_deallocate_list /free_deallocate_list
在《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<Metadata*>* _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遍歷到,其定義如下:
其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方法的調用鏈如下:
2、ChunkedHandleList
ChunkedHandleList也是ClassLoaderData的內部類,其定義如下:
一個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方法的調用鏈如下:
3、JNIMethodBlock
JNIMethodBlock用來生成jmethodID的,每個jmethodID實際是一個Method**。JNIMethodBlock的定義如下:
其結構跟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,該方法的調用鏈如下:
make_jmethod_id方法的實現如下:
生成的jmethodID實際就是add_method方法返回的Method**。
4、init_null_class_loader_data / init_dependencies
這兩個方法都是用來初始化啓動類加載器對應的_the_null_class_loader_data屬性,都是在Universe初始化的時候調用的,其調用鏈如下:
兩方法的源碼如下:
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!");
}
}
重點關注其調用鏈,如下:
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方法的實現,如下:
該方法的調用鏈如下:
7、add_to_deallocate_list /free_deallocate_list
add_to_deallocate_list用於臨時保存需要被釋放的Klass,Method等元數據的指針,因爲這些元數據可能依然被使用,所以不能立即釋放,只能等到類加載器被卸載了才釋放。free_deallocate_list是類加載器被卸載時調用來釋放deallocate_list中的元數據,這兩方法的調用鏈如下:
這兩方法的源碼如下:
// 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<Metadata*>(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是一個模板方法,該方法的實現如下:
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鏈表中移除,這兩方法的調用鏈如下:
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,其定義的屬性和方法都是靜態的,屬性如下:
其中head表示當前活躍的ClassLoaderData鏈表,unloading表示即將被卸載的ClassLoaderData鏈表,通過do_unloading方法將某個不再活躍的ClassLoaderData加入到unloading鏈表中,最終由purge方法觸發unloading鏈表中所有ClassLoaderData的內存釋放。定義的方法主要是GC遍歷相關的,如下:
其實現都是通過_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,該方法的調用鏈如下:
該方法的源碼如下:
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類加載器被卸載。該方法的調用鏈如下:
該方法的源碼如下:
// 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();
}