importjava.lang.reflect.Method;importjava.net.URL;/** * Created by nijiaben on 4/22/16. */publicclassTTest{privateObjectaaa;publicstaticvoidmain(Stringargs[]){try{TTesttt=newTTest();//将对象移到old,并置空aaa的aab属性test(tt);//清理掉aab对象System.gc();System.out.println("finished");}catch(Exceptione){e.printStackTrace();}}@SuppressWarnings("resource")publicstaticvoidtest(TTesttt){try{//创建一个新的类加载器,从AAA.jar里加载AAA类URL[]urls=newURL[1];urls[0]=newURL("file:///home/nijiaben/tmp/AAA.jar");tt.aaa=newTestLoader(urls).loadClass("AAA").newInstance();//保证类加载器对象能进入到old里,因为ygc是不会对classLoader做清理的for(inti=0;i<10;i++){System.gc();Thread.sleep(1000);}//将aaa里的aab属性清空掉,以便在后面gc的时候能清理掉aab对象,这样AAB的类加载器其实就没有什么地方有强引用了,在full gc的时候能被回收Method[]methods=tt.aaa.getClass().getDeclaredMethods();for(Methodm:methods){if(m.getName().equals("clear")){m.invoke(tt.aaa);break;}}}catch(Exceptione){e.printStackTrace();}}}
classClassLoaderData:publicCHeapObj<mtClass>{...staticClassLoaderData*_the_null_class_loader_data;oop_class_loader;// oop used to uniquely identify a class loader// class loader or a canonical class pathDependencies_dependencies;// holds dependencies from this class loader// data to others.Metaspace*_metaspace;// Meta-space where meta-data defined by the// classes in the class loader are allocated.Mutex*_metaspace_lock;// Locks the metaspace for allocations and setup.bool_unloading;// true if this class loader goes awaybool_keep_alive;// if this CLD is kept alive without a keep_alive_object().bool_is_anonymous;// if this CLD is for an anonymous classvolatileint_claimed;// true if claimed, for example during GC traces.// To avoid applying oop closure more than once.// Has to be an int because we cas it.Klass*_klasses;// The classes defined by the class loader.JNIHandleBlock*_handles;// Handles to constant pool arrays// These method IDs are created for the class loader and set to NULL when the// class loader is unloaded. They are rarely freed, only for redefine classes// and if they lose a data race in InstanceKlass.JNIMethodBlock*_jmethod_ids;// Metadata to be deallocated when it's safe at class unloading, when// this class loader isn't unloaded itself.GrowableArray<Metadata*>*_deallocate_list;// Support for walking class loader data objectsClassLoaderData*_next;/// Next loader_datas created// ReadOnly and ReadWrite metaspaces (static because only on the null// class loader for now).staticMetaspace*_ro_metaspace;staticMetaspace*_rw_metaspace;...}
ClassLoaderData::ClassLoaderData(Handleh_class_loader,boolis_anonymous,Dependenciesdependencies):_class_loader(h_class_loader()),_is_anonymous(is_anonymous),// An anonymous class loader data doesn't have anything to keep// it from being unloaded during parsing of the anonymous class.// The null-class-loader should always be kept alive._keep_alive(is_anonymous||h_class_loader.is_null()),_metaspace(NULL),_unloading(false),_klasses(NULL),_claimed(0),_jmethod_ids(NULL),_handles(NULL),_deallocate_list(NULL),_next(NULL),_dependencies(dependencies),_metaspace_lock(newMutex(Monitor::leaf+1,"Metaspace allocation lock",true)){// empty}
UNSAFE_ENTRY(jclass,Unsafe_DefineAnonymousClass(JNIEnv*env,jobjectunsafe,jclasshost_class,jbyteArraydata,jobjectArraycp_patches_jh)){instanceKlassHandleanon_klass;jobjectres_jh=NULL;UnsafeWrapper("Unsafe_DefineAnonymousClass");ResourceMarkrm(THREAD);HeapWord*temp_alloc=NULL;anon_klass=Unsafe_DefineAnonymousClass_impl(env,host_class,data,cp_patches_jh,&temp_alloc,THREAD);if(anon_klass()!=NULL)res_jh=JNIHandles::make_local(env,anon_klass->java_mirror());// try/finally clause:if(temp_alloc!=NULL){FREE_C_HEAP_ARRAY(HeapWord,temp_alloc,mtInternal);}// The anonymous class loader data has been artificially been kept alive to// this point. The mirror and any instances of this class have to keep// it alive afterwards.if(anon_klass()!=NULL){anon_klass->class_loader_data()->set_keep_alive(false);}// let caller initialize it as needed...return(jclass)res_jh;}UNSAFE_END}
Klass*SystemDictionary::parse_stream(Symbol*class_name,Handleclass_loader,Handleprotection_domain,ClassFileStream*st,KlassHandlehost_klass,GrowableArray<Handle>*cp_patches,TRAPS){TempNewSymbolparsed_name=NULL;Ticksclass_load_start_time=Ticks::now();ClassLoaderData*loader_data;if(host_klass.not_null()){// Create a new CLD for anonymous class, that uses the same class loader// as the host_klassassert(EnableInvokeDynamic,"");guarantee(host_klass->class_loader()==class_loader(),"should be the same");guarantee(!DumpSharedSpaces,"must not create anonymous classes when dumping");loader_data=ClassLoaderData::anonymous_class_loader_data(class_loader(),CHECK_NULL);loader_data->record_dependency(host_klass(),CHECK_NULL);}else{loader_data=ClassLoaderData::class_loader_data(class_loader());}instanceKlassHandlek=ClassFileParser(st).parseClassFile(class_name,loader_data,protection_domain,host_klass,cp_patches,parsed_name,true,THREAD);...}ClassLoaderData*ClassLoaderData::anonymous_class_loader_data(ooploader,TRAPS){// Add a new class loader data to the graph.returnClassLoaderDataGraph::add(loader,true,CHECK_NULL);}ClassLoaderData*ClassLoaderDataGraph::add(Handleloader,boolis_anonymous,TRAPS){// We need to allocate all the oops for the ClassLoaderData before allocating the// actual ClassLoaderData object.ClassLoaderData::Dependenciesdependencies(CHECK_NULL);No_Safepoint_Verifierno_safepoints;// we mustn't GC until we've installed the// ClassLoaderData in the graph since the CLD// contains unhandled oopsClassLoaderData*cld=newClassLoaderData(loader,is_anonymous,dependencies);...}