java 加载到内存_java classloader是怎么加载自身到内存里面执行的?

本文深入探讨JVM的类加载机制,包括VMClassloader、ExtClassLoader、AppClassLoader和自定义类加载器的角色。重点解析HotSpotVM中类加载的源码实现,特别是BootstrapClassLoader和双亲委派模型。通过代码分析,展示了类从查找、解析到加载的详细步骤,强调了类加载的安全性和效率。
摘要由CSDN通过智能技术生成

默认题主对JVM的类加载机制了解不是很深入,VM Classloader、ExtClassLoader、AppClassLoader、AppletClassLoader以及自定义类加载器的作用,以及双亲委派机制等基本知识请自行baidu,很多技术博客对此都有诠释,在此不再赘述。

其中ExtClassLoader和AppClassLoader都是Java实现的,VM ClassLoader作为HotSpot VM实现的一部分使用C++实现,不管是ExtClassLoader,抑或AppClassLoader,还是其他在VM ClassLoader管辖的class文件都会一视同仁地通过Bootstrap ClassLoader加载,需要说明的是VM ClassLoader是一个顶级加载器,意味着它是没有父加载器的。

具体到题主问的问题,就HotSpot VM而言,上述的加载过程实现的很明确,可以直接贴代码了:

instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {

ResourceMark rm(THREAD);

EventMark m("loading class %s", h_name->as_C_string());

ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);

stringStream st;

// st.print() uses too much stack space while handling a StackOverflowError // st.print("%s.class", h_name->as_utf8()); st.print_raw(h_name->as_utf8());

st.print_raw(".class");

char* name = st.as_string();

// Lookup stream for parsing .class file ClassFileStream* stream = NULL;

int classpath_index = 0;

{

PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),

((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(),

PerfClassTraceTime::CLASS_LOAD);

ClassPathEntry* e = _first_entry;

while (e != NULL) {

stream = e->open_stream(name, CHECK_NULL);

if (stream != NULL) {

break;

}

e = e->next();

++classpath_index;

}

}

instanceKlassHandle h;

if (stream != NULL) {

// class file found, parse it ClassFileParser parser(stream);

ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();

Handle protection_domain;

TempNewSymbol parsed_name = NULL;

instanceKlassHandle result = parser.parseClassFile(h_name,

loader_data,

protection_domain,

parsed_name,

false,

CHECK_(h));

// add to package table if (add_package(name, classpath_index, THREAD)) {

h = result;

}

}

return h;

}

这个函数是这么被调用的:

instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {

instanceKlassHandle nh = instanceKlassHandle(); // null Handle

if (class_loader.is_null()) {

// Search the shared system dictionary for classes preloaded into the

// shared spaces.

instanceKlassHandle k;

{

PerfTraceTime vmtimer(ClassLoader::perf_shared_classload_time());

k = load_shared_class(class_name, class_loader, THREAD);

}

if (k.is_null()) {

// Use VM class loader

PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time());

k = ClassLoader::load_classfile(class_name, CHECK_(nh));

}

// find_or_define_instance_class may return a different InstanceKlass

if (!k.is_null()) {

k = find_or_define_instance_class(class_name, class_loader, k, CHECK_(nh));

}

return k;

} else {

// Use user specified class loader to load class. Call loadClass operation on class_loader.

ResourceMark rm(THREAD);

assert(THREAD->is_Java_thread(), "must be a JavaThread");

JavaThread* jt = (JavaThread*) THREAD;

PerfClassTraceTime vmtimer(ClassLoader::perf_app_classload_time(),

ClassLoader::perf_app_classload_selftime(),

ClassLoader::perf_app_classload_count(),

jt->get_thread_stat()->perf_recursion_counts_addr(),

jt->get_thread_stat()->perf_timers_addr(),

PerfClassTraceTime::CLASS_LOAD);

Handle s = java_lang_String::create_from_symbol(class_name, CHECK_(nh));

// Translate to external class name format, i.e., convert '/' chars to '.'

Handle string = java_lang_String::externalize_classname(s, CHECK_(nh));

JavaValue result(T_OBJECT);

KlassHandle spec_klass (THREAD, SystemDictionary::ClassLoader_klass());

// Call public unsynchronized loadClass(String) directly for all class loaders

// for parallelCapable class loaders. JDK >=7, loadClass(String, boolean) will

// acquire a class-name based lock rather than the class loader object lock.

// JDK < 7 already acquire the class loader lock in loadClass(String, boolean),

// so the call to loadClassInternal() was not required.

//

// UnsyncloadClass flag means both call loadClass(String) and do

// not acquire the class loader lock even for class loaders that are

// not parallelCapable. This was a risky transitional

// flag for diagnostic purposes only. It is risky to call

// custom class loaders without synchronization.

// WARNING If a custom class loader does NOT synchronizer findClass, or callers of

// findClass, the UnsyncloadClass flag risks unexpected timing bugs in the field.

// Do NOT assume this will be supported in future releases.

//

// Added MustCallLoadClassInternal in case we discover in the field

// a customer that counts on this call

if (MustCallLoadClassInternal && has_loadClassInternal()) {

JavaCalls::call_special(&result,

class_loader,

spec_klass,

vmSymbols::loadClassInternal_name(),

vmSymbols::string_class_signature(),

string,

CHECK_(nh));

} else {

JavaCalls::call_virtual(&result,

class_loader,

spec_klass,

vmSymbols::loadClass_name(),

vmSymbols::string_class_signature(),

string,

CHECK_(nh));

}

assert(result.get_type() == T_OBJECT, "just checking");

oop obj = (oop) result.get_jobject();

// Primitive classes return null since forName() can not be

// used to obtain any of the Class objects representing primitives or void

if ((obj != NULL) && !(java_lang_Class::is_primitive(obj))) {

instanceKlassHandle k =

instanceKlassHandle(THREAD, java_lang_Class::as_Klass(obj));

// For user defined Java class loaders, check that the name returned is

// the same as that requested. This check is done for the bootstrap

// loader when parsing the class file.

if (class_name == k->name()) {

return k;

}

}

// Class is not found or has the wrong name, return NULL

return nh;

}

}

这里可以看到根据参数class_loader句柄是否为null,采用了不同的加载机制~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值