// Find a command line agent library and return its entry point for
// -agentlib: -agentpath: -Xrun
// num_symbol_entries must be passed-in since only the caller knows the number of symbols in the array.
查找命令行代理点并返回它的入口
由于只有调用方知道它的编码,所以num_symbol_entries必须被传入
staticOnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_symbols[], size_t num_symbol_entries) {
OnLoadEntry_t on_load_entry = NULL;
void *library = agent->os_lib(); // check if we have looked it up before
if (library == NULL) {
char buffer[JVM_MAXPATHLEN];
char ebuf[1024];
const char *name = agent->name();
const char*msg = "Could not find agent library ";
if (agent->is_absolute_path()) {
library = os::dll_load(name, ebuf, sizeof ebuf);
if (library == NULL) {
const char*sub_msg = " in absolute path, with error: ";
size_t len = strlen(msg) + strlen(name) + strlen(sub_msg) + strlen(ebuf) + 1;
char *buf = NEW_C_HEAP_ARRAY(char, len);
jio_snprintf(buf, len, "%s%s%s%s", msg, name, sub_msg, ebuf);
// If we can't find the agent, exit.
vm_exit_during_initialization(buf, NULL);
FREE_C_HEAP_ARRAY(char, buf);
}
} else {
// Try to load the agent from the standard dll directory
尝试从标准dll库中加载代理
os::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), name);
library = os::dll_load(buffer, ebuf, sizeof ebuf);
#ifdef KERNEL
// Download instrument dll
if(library == NULL && strcmp(name, "instrument") == 0) {
char *props = Arguments::get_kernel_properties();
char *home = Arguments::get_java_home();
const char*fmt = "%s/bin/java %s -Dkernel.background.download=false"
" sun.jkernel.DownloadManager -download client_jvm";
size_t length = strlen(props) + strlen(home) + strlen(fmt) + 1;
char *cmd = NEW_C_HEAP_ARRAY(char, length);
jio_snprintf(cmd, length, fmt, home, props);
int status = os::fork_and_exec(cmd);
FreeHeap(props);
if (status == -1) {
warning(cmd);
vm_exit_during_initialization("fork_and_exec failed: %s",
strerror(errno));
}
FREE_C_HEAP_ARRAY(char, cmd);
// when this comes back the instrument.dll should be where it belongs.
当返回结果时候,instrument.dll 应该归属它应该在的位置
library = os::dll_load(buffer, ebuf, sizeof ebuf);
}
#endif // KERNEL
if(library == NULL) { // Try the local directory
char ns[1] = {0};
os::dll_build_name(buffer, sizeof(buffer), ns, name);
library = os::dll_load(buffer, ebuf, sizeof ebuf);
if (library == NULL) {
const char*sub_msg = " on the library path, with error: ";
size_t len = strlen(msg) + strlen(name) + strlen(sub_msg) + strlen(ebuf) + 1;
char *buf = NEW_C_HEAP_ARRAY(char, len);
jio_snprintf(buf, len, "%s%s%s%s", msg, name, sub_msg, ebuf);
// If we can't find the agent, exit.
vm_exit_during_initialization(buf, NULL);
FREE_C_HEAP_ARRAY(char, buf);
}
}
}
agent->set_os_lib(library);
}
// Find the OnLoad function.
for (size_t symbol_index = 0; symbol_index < num_symbol_entries; symbol_index++) {
on_load_entry = CAST_TO_FN_PTR(OnLoadEntry_t, os::dll_lookup(library, on_load_symbols[symbol_index]));
if(on_load_entry != NULL) break;
}
return on_load_entry;
}
此函数的具体功能,应该就是根据路径找到jar包,解压并形成数据流放入c内存中。
// Called for after the VM is initialized for -Xrun libraries which have not been converted to agent libraries
// Invokes JVM_OnLoad
初始化虚拟机之后,调用尚未转换为代理库的-Xrun 库
void Threads::create_vm_init_libraries() {
extern struct JavaVM_ main_vm;
AgentLibrary* agent;
for (agent = Arguments::libraries(); agent != NULL; agent = agent->next()) {
OnLoadEntry_t on_load_entry = lookup_jvm_on_load(agent);
if (on_load_entry != NULL) {
// Invoke the JVM_OnLoad function
JavaThread* thread = JavaThread::current();
ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread);
jint err = (*on_load_entry)(&main_vm, agent->options(), NULL);
if (err != JNI_OK) {
vm_exit_during_initialization("-Xrun library failed to init", agent->name());
}
} else {
vm_exit_during_initialization("Could not find JVM_OnLoad function in -Xrun library", agent->name());
}
}
}
此函数意义大概是:加载c类库/jar
// Initialize the class loader's access to methods in libzip. Parse and
// process the boot classpath into a list ClassPathEntry objects. Once
// this list has been created, it must not change order (see class PackageInfo)
// it can be appended to and is by jvmti and the kernel vm.
void ClassLoader::initialize() {
assert(_package_hash_table == NULL, "should have been initialized by now.");
EXCEPTION_MARK;
if (UsePerfData) {
// jvmstat performance counters
NEWPERFTICKCOUNTER(_perf_accumulated_time, SUN_CLS, "time");
NEWPERFTICKCOUNTER(_perf_class_init_time, SUN_CLS, "classInitTime");
NEWPERFTICKCOUNTER(_perf_class_init_selftime, SUN_CLS, "classInitTime.self");
NEWPERFTICKCOUNTER(_perf_class_verify_time, SUN_CLS, "classVerifyTime");
NEWPERFTICKCOUNTER(_perf_class_verify_selftime, SUN_CLS, "classVerifyTime.self");
NEWPERFTICKCOUNTER(_perf_class_link_time, SUN_CLS, "classLinkedTime");
NEWPERFTICKCOUNTER(_perf_class_link_selftime, SUN_CLS, "classLinkedTime.self");
NEWPERFEVENTCOUNTER(_perf_classes_inited, SUN_CLS, "initializedClasses");
NEWPERFEVENTCOUNTER(_perf_classes_linked, SUN_CLS, "linkedClasses");
NEWPERFEVENTCOUNTER(_perf_classes_verified, SUN_CLS, "verifiedClasses");
NEWPERFTICKCOUNTER(_perf_class_parse_time, SUN_CLS, "parseClassTime");
NEWPERFTICKCOUNTER(_perf_class_parse_selftime, SUN_CLS, "parseClassTime.self");
NEWPERFTICKCOUNTER(_perf_sys_class_lookup_time, SUN_CLS, "lookupSysClassTime");
NEWPERFTICKCOUNTER(_perf_shared_classload_time, SUN_CLS, "sharedClassLoadTime");
NEWPERFTICKCOUNTER(_perf_sys_classload_time, SUN_CLS, "sysClassLoadTime");
NEWPERFTICKCOUNTER(_perf_app_classload_time, SUN_CLS, "appClassLoadTime");
NEWPERFTICKCOUNTER(_perf_app_classload_selftime, SUN_CLS, "appClassLoadTime.self");
NEWPERFEVENTCOUNTER(_perf_app_classload_count, SUN_CLS, "appClassLoadCount");
NEWPERFTICKCOUNTER(_perf_define_appclasses, SUN_CLS, "defineAppClasses");
NEWPERFTICKCOUNTER(_perf_define_appclass_time, SUN_CLS, "defineAppClassTime");
NEWPERFTICKCOUNTER(_perf_define_appclass_selftime, SUN_CLS, "defineAppClassTime.self");
NEWPERFBYTECOUNTER(_perf_app_classfile_bytes_read, SUN_CLS, "appClassBytes");
NEWPERFBYTECOUNTER(_perf_sys_classfile_bytes_read, SUN_CLS, "sysClassBytes");
// The following performance counters are added for measuring the impact
// of the bug fix of 6365597\. They are mainly focused on finding out
// the behavior of system & user-defined classloader lock, whether
// ClassLoader.loadClass/findClass is being called synchronized or not.
// Also two additional counters are created to see whether 'UnsyncloadClass'
// flag is being set or not and how many times load_instance_class call
// fails with linkageError etc.
NEWPERFEVENTCOUNTER(_sync_systemLoaderLockContentionRate, SUN_CLS,
"systemLoaderLockContentionRate");
NEWPERFEVENTCOUNTER(_sync_nonSystemLoaderLockContentionRate, SUN_CLS,
"nonSystemLoaderLockContentionRate");
NEWPERFEVENTCOUNTER(_sync_JVMFindLoadedClassLockFreeCounter, SUN_CLS,
"jvmFindLoadedClassNoLockCalls");
NEWPERFEVENTCOUNTER(_sync_JVMDefineClassLockFreeCounter, SUN_CLS,
"jvmDefineClassNoLockCalls");
NEWPERFEVENTCOUNTER(_sync_JNIDefineClassLockFreeCounter, SUN_CLS,
"jniDefineClassNoLockCalls");
NEWPERFEVENTCOUNTER(_unsafe_defineClassCallCounter, SUN_CLS,
"unsafeDefineClassCalls");
NEWPERFEVENTCOUNTER(_isUnsyncloadClass, SUN_CLS, "isUnsyncloadClassSet");
NEWPERFEVENTCOUNTER(_load_instance_class_failCounter, SUN_CLS,
"loadInstanceClassFailRate");
// increment the isUnsyncloadClass counter if UnsyncloadClass is set.
if (UnsyncloadClass) {
_isUnsyncloadClass->inc();
}
}
// lookup zip library entry points
load_zip_library();
// initialize search path
setup_bootstrap_search_path();
if (LazyBootClassLoader) {
// set up meta index which makes boot classpath initialization lazier
setup_meta_index();
}
}
加载zip解压库,解压jar包,初始化bootstrap的classloader路径,
即:找到bootstrap的系统路径,将路径按分隔符拆解,依次解压到ClassPathEntry中去。
PS:与java代码的classloader不同,此处的c代码是要对流的操作。
void vm_init_globals() {
check_ThreadShadow();
basic_types_init();
eventlog_init();
mutex_init();
chunkpool_init();
perfMemory_init();
}
// Initialize system properties key and value.
void Arguments::init_system_properties() {
PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.name",
"Java Virtual Machine Specification", false));
PropertyList_add(&_system_properties, new SystemProperty("java.vm.version", VM_Version::vm_release(), false));
PropertyList_add(&_system_properties, new SystemProperty("java.vm.name", VM_Version::vm_name(), false));
PropertyList_add(&_system_properties, new SystemProperty("java.vm.info", VM_Version::vm_info_string(), true));
// following are JVMTI agent writeable properties.
// Properties values are set to NULL and they are
// os specific they are initialized in os::init_system_properties_values().
_java_ext_dirs = new SystemProperty("java.ext.dirs", NULL, true);
_java_endorsed_dirs = new SystemProperty("java.endorsed.dirs", NULL, true);
_sun_boot_library_path = new SystemProperty("sun.boot.library.path", NULL, true);
_java_library_path = new SystemProperty("java.library.path", NULL, true);
_java_home = new SystemProperty("java.home", NULL, true);
_sun_boot_class_path = new SystemProperty("sun.boot.class.path", NULL, true);
_java_class_path = new SystemProperty("java.class.path", "", true);
// Add to System Property list.
PropertyList_add(&_system_properties, _java_ext_dirs);
PropertyList_add(&_system_properties, _java_endorsed_dirs);
PropertyList_add(&_system_properties, _sun_boot_library_path);
PropertyList_add(&_system_properties, _java_library_path);
PropertyList_add(&_system_properties, _java_home);
PropertyList_add(&_system_properties, _java_class_path);
PropertyList_add(&_system_properties, _sun_boot_class_path);
// Set OS specific system properties values
os::init_system_properties_values();
}
void os::init_system_properties_values() {
/* sysclasspath, java_home, dll_dir */
{
char *home_path;
char *dll_path;
char *pslash;
char*bin = "\\bin";
char home_dir[MAX_PATH];
if (!getenv("_ALT_JAVA_HOME_DIR", home_dir, MAX_PATH)) {
os::jvm_path(home_dir, sizeof(home_dir));
// Found the full path to jvm[_g].dll.
// Now cut the path to /jre if we can.
*(strrchr(home_dir, '\\')) = '\0'; /* get rid of \jvm.dll */
pslash = strrchr(home_dir, '\\');
if (pslash != NULL) {
*pslash = '\0'; /* get rid of \{client|server} */
pslash = strrchr(home_dir, '\\');
if (pslash != NULL)
*pslash = '\0'; /* get rid of \bin */
}
}
home_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + 1);
if (home_path == NULL)
return;
strcpy(home_path, home_dir);
Arguments::set_java_home(home_path);
dll_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + strlen(bin) + 1);
if (dll_path == NULL)
return;
strcpy(dll_path, home_dir);
strcat(dll_path, bin);
Arguments::set_dll_dir(dll_path);
if (!set_boot_path('\\', ';'))
return;
}
/* library_path */
#defineEXT_DIR "\\lib\\ext"
#defineBIN_DIR "\\bin"
#definePACKAGE_DIR "\\Sun\\Java"
{
/* Win32 library search order (See the documentation for LoadLibrary):
*
* 1\. The directory from which application is loaded.
* 2\. The system wide Java Extensions directory (Java only)
* 3\. System directory (GetSystemDirectory)
* 4\. Windows directory (GetWindowsDirectory)
* 5\. The PATH environment variable
* 6\. The current directory
*/
char *library_path;
char tmp[MAX_PATH];
char *path_str = ::getenv("PATH");
library_path = NEW_C_HEAP_ARRAY(char, MAX_PATH * 5 + sizeof(PACKAGE_DIR) +
sizeof(BIN_DIR) + (path_str ? strlen(path_str) : 0) + 10);
library_path[0] = '\0';
GetModuleFileName(NULL, tmp, sizeof(tmp));
*(strrchr(tmp, '\\')) = '\0';
strcat(library_path, tmp);
GetWindowsDirectory(tmp, sizeof(tmp));
strcat(library_path, ";");
strcat(library_path, tmp);
strcat(library_path, PACKAGE_DIR BIN_DIR);
GetSystemDirectory(tmp, sizeof(tmp));
strcat(library_path, ";");
strcat(library_path, tmp);
GetWindowsDirectory(tmp, sizeof(tmp));
strcat(library_path, ";");
strcat(library_path, tmp);
if (path_str) {
strcat(library_path, ";");
strcat(library_path, path_str);
}
strcat(library_path, ";.");
Arguments::set_library_path(library_path);
FREE_C_HEAP_ARRAY(char, library_path);
}
/* Default extensions directory */
{
char path[MAX_PATH];
charbuf[2 * MAX_PATH + 2 * sizeof(EXT_DIR) + sizeof(PACKAGE_DIR) + 1];
GetWindowsDirectory(path, MAX_PATH);
sprintf(buf, "%s%s;%s%s%s", Arguments::get_java_home(), EXT_DIR,
path, PACKAGE_DIR, EXT_DIR);
Arguments::set_ext_dirs(buf);
}
#undef EXT_DIR
#undef BIN_DIR
#undef PACKAGE_DIR
/* Default endorsed standards directory. */
{
#defineENDORSED_DIR "\\lib\\endorsed"
size_t len = strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR);
char * buf = NEW_C_HEAP_ARRAY(char, len);
sprintf(buf, "%s%s", Arguments::get_java_home(), ENDORSED_DIR);
Arguments::set_endorsed_dirs(buf);
#undef ENDORSED_DIR
}
#ifndef _WIN64
// set our UnhandledExceptionFilter and save any previous one
prev_uef_handler = SetUnhandledExceptionFilter(Handle_FLT_Exception);
#endif
// Done
return;
}
void os::init_system_properties_values() {
/* sysclasspath, java_home, dll_dir */
{
char *home_path;
char *dll_path;
char *pslash;
char*bin = "\\bin";
char home_dir[MAX_PATH];
if (!getenv("_ALT_JAVA_HOME_DIR", home_dir, MAX_PATH)) {
os::jvm_path(home_dir, sizeof(home_dir));
// Found the full path to jvm[_g].dll.
// Now cut the path to /jre if we can.
*(strrchr(home_dir, '\\')) = '\0'; /* get rid of \jvm.dll */
pslash = strrchr(home_dir, '\\');
if (pslash != NULL) {
*pslash = '\0'; /* get rid of \{client|server} */
pslash = strrchr(home_dir, '\\');
if (pslash != NULL)
*pslash = '\0'; /* get rid of \bin */
}
}
home_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + 1);
if (home_path == NULL)
return;
strcpy(home_path, home_dir);
Arguments::set_java_home(home_path);
dll_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + strlen(bin) + 1);
if (dll_path == NULL)
return;
strcpy(dll_path, home_dir);
strcat(dll_path, bin);
Arguments::set_dll_dir(dll_path);
if (!set_boot_path('\\', ';'))
return;
}
/* library_path */
#defineEXT_DIR "\\lib\\ext"
#defineBIN_DIR "\\bin"
#definePACKAGE_DIR "\\Sun\\Java"
{
/* Win32 library search order (See the documentation for LoadLibrary):
*
* 1\. The directory from which application is loaded.
* 2\. The system wide Java Extensions directory (Java only)
* 3\. System directory (GetSystemDirectory)
* 4\. Windows directory (GetWindowsDirectory)
* 5\. The PATH environment variable
* 6\. The current directory
*/
char *library_path;
char tmp[MAX_PATH];
char *path_str = ::getenv("PATH");
library_path = NEW_C_HEAP_ARRAY(char, MAX_PATH * 5 + sizeof(PACKAGE_DIR) +
sizeof(BIN_DIR) + (path_str ? strlen(path_str) : 0) + 10);
library_path[0] = '\0';
GetModuleFileName(NULL, tmp, sizeof(tmp));
*(strrchr(tmp, '\\')) = '\0';
strcat(library_path, tmp);
GetWindowsDirectory(tmp, sizeof(tmp));
strcat(library_path, ";");
strcat(library_path, tmp);
strcat(library_path, PACKAGE_DIR BIN_DIR);
GetSystemDirectory(tmp, sizeof(tmp));
strcat(library_path, ";");
strcat(library_path, tmp);
GetWindowsDirectory(tmp, sizeof(tmp));
strcat(library_path, ";");
strcat(library_path, tmp);
if (path_str) {
strcat(library_path, ";");
strcat(library_path, path_str);
}
strcat(library_path, ";.");
Arguments::set_library_path(library_path);
FREE_C_HEAP_ARRAY(char, library_path);
}
/* Default extensions directory */
{
char path[MAX_PATH];
charbuf[2 * MAX_PATH + 2 * sizeof(EXT_DIR) + sizeof(PACKAGE_DIR) + 1];
GetWindowsDirectory(path, MAX_PATH);
sprintf(buf, "%s%s;%s%s%s", Arguments::get_java_home(), EXT_DIR,
path, PACKAGE_DIR, EXT_DIR);
Arguments::set_ext_dirs(buf);
}
#undef EXT_DIR
#undef BIN_DIR
#undef PACKAGE_DIR
/* Default endorsed standards directory. */
{
#defineENDORSED_DIR "\\lib\\endorsed"
size_t len = strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR);
char * buf = NEW_C_HEAP_ARRAY(char, len);
sprintf(buf, "%s%s", Arguments::get_java_home(), ENDORSED_DIR);
Arguments::set_endorsed_dirs(buf);
#undef ENDORSED_DIR
}
#ifndef _WIN64
// set our UnhandledExceptionFilter and save any previous one
prev_uef_handler = SetUnhandledExceptionFilter(Handle_FLT_Exception);
#endif
// Done
return;
}
bool os::set_boot_path(charfileSep, char pathSep) {
const char* home = Arguments::get_java_home();
int home_len = (int)strlen(home);
static const char* meta_index_dir_format = "%/lib/";
static const char* meta_index_format = "%/lib/meta-index";
char* meta_index = format_boot_path(meta_index_format, home, home_len, fileSep, pathSep);
if(meta_index == NULL) return false;
char* meta_index_dir = format_boot_path(meta_index_dir_format, home, home_len, fileSep, pathSep);
if(meta_index_dir == NULL) return false;
Arguments::set_meta_index_path(meta_index, meta_index_dir);
// Any modification to the JAR-file list, for the boot classpath must be
// aligned with install/install/make/common/Pack.gmk. Note: boot class
// path class JARs, are stripped for StackMapTable to reduce download size.
static const char classpath_format[] =
"%/lib/resources.jar:"
"%/lib/rt.jar:"
"%/lib/sunrsasign.jar:"
"%/lib/jsse.jar:"
"%/lib/jce.jar:"
"%/lib/charsets.jar:"
"%/classes";
char* sysclasspath = format_boot_path(classpath_format, home, home_len, fileSep, pathSep);
if(sysclasspath == NULL) return false;
Arguments::set_sysclasspath(sysclasspath);
return true;
}
// Support parallel classloading
// All parallel class loaders, including bootstrap classloader
// lock a placeholder entry for this class/class_loader pair
// to allow parallel defines of different classes for this class loader
// With AllowParallelDefine flag==true, in case they do not synchronize around
// FindLoadedClass/DefineClass, calls, we check for parallel
// loading for them, wait if a defineClass is in progress
// and return the initial requestor's results
// This flag does not apply to the bootstrap classloader.
// With AllowParallelDefine flag==false, call through to define_instance_class
// which will throw LinkageError: duplicate class definition.
// False is the requested default.
// For better performance, the class loaders should synchronize
// findClass(), i.e. FindLoadedClass/DefineClassIfAbsent or they
// potentially waste time reading and parsing the bytestream.
// Note: VM callers should ensure consistency of k/class_name,class_loader
instanceKlassHandle SystemDictionary::find_or_define_instance_class(Symbol* class_name, Handle class_loader, instanceKlassHandle k, TRAPS) {
instanceKlassHandle nh = instanceKlassHandle(); // null Handle
Symbol* name_h = k->name(); // passed in class_name may be null
unsigned int d_hash = dictionary()->compute_hash(name_h, class_loader);
int d_index = dictionary()->hash_to_index(d_hash);
// Hold SD lock around find_class and placeholder creation for DEFINE_CLASS
unsigned int p_hash = placeholders()->compute_hash(name_h, class_loader);
int p_index = placeholders()->hash_to_index(p_hash);
PlaceholderEntry* probe;
{
MutexLocker mu(SystemDictionary_lock, THREAD);
// First check if class already defined
if (UnsyncloadClass || (is_parallelDefine(class_loader))) {
klassOop check = find_class(d_index, d_hash, name_h, class_loader);
if (check != NULL) {
return(instanceKlassHandle(THREAD, check));
}
}
// Acquire define token for this class/classloader
probe = placeholders()->find_and_add(p_index, p_hash, name_h, class_loader, PlaceholderTable::DEFINE_CLASS, NULL, THREAD);
// Wait if another thread defining in parallel
// All threads wait - even those that will throw duplicate class: otherwise
// caller is surprised by LinkageError: duplicate, but findLoadedClass fails
// if other thread has not finished updating dictionary
while (probe->definer() != NULL) {
SystemDictionary_lock->wait();
}
// Only special cases allow parallel defines and can use other thread's results
// Other cases fall through, and may run into duplicate defines
// caught by finding an entry in the SystemDictionary
if ((UnsyncloadClass || is_parallelDefine(class_loader)) && (probe->instanceKlass() != NULL)) {
probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS);
placeholders()->find_and_remove(p_index, p_hash, name_h, class_loader, THREAD);
SystemDictionary_lock->notify_all();
#ifdef ASSERT
klassOop check = find_class(d_index, d_hash, name_h, class_loader);
assert(check != NULL, "definer missed recording success");
#endif
return(instanceKlassHandle(THREAD, probe->instanceKlass()));
} else {
// This thread will define the class (even if earlier thread tried and had an error)
probe->set_definer(THREAD);
}
}
define_instance_class(k, THREAD);
Handle linkage_exception = Handle(); // null handle
// definer must notify any waiting threads
{
MutexLocker mu(SystemDictionary_lock, THREAD);
PlaceholderEntry* probe = placeholders()->get_entry(p_index, p_hash, name_h, class_loader);
assert(probe != NULL, "DEFINE_CLASS placeholder lost?");
if (probe != NULL) {
if (HAS_PENDING_EXCEPTION) {
linkage_exception = Handle(THREAD,PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
} else {
probe->set_instanceKlass(k());
}
probe->set_definer(NULL);
probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS);
placeholders()->find_and_remove(p_index, p_hash, name_h, class_loader, THREAD);
SystemDictionary_lock->notify_all();
}
}
// Can't throw exception while holding lock due to rank ordering
if (linkage_exception() != NULL) {
THROW_OOP_(linkage_exception(), nh); // throws exception and returns
}
return k;
}
protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class> c = findLoadedClass(name); if (c == null) { long t0 = System.*nanoTime*(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.*nanoTime*(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.*getParentDelegationTime*().addTime(t1 - t0); sun.misc.PerfCounter.*getFindClassTime*().addElapsedTimeFrom(t1); sun.misc.PerfCounter.*getFindClasses*().increment(); } } if (resolve) { resolveClass(c); } return c; } }
public Launcher() { Launcher.ExtClassLoader var1; try { var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try { this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } Thread.currentThread().setContextClassLoader(this.loader); String var2 = System.getProperty("java.security.manager"); if (var2 != null) { SecurityManager var3 = null; if (!"".equals(var2) && !"default".equals(var2)) { try { var3 = (SecurityManager)this.loader.loadClass(var2).newInstance(); } catch (IllegalAccessException var5) { ; } catch (InstantiationException var6) { ; } catch (ClassNotFoundException var7) { ; } catch (ClassCastException var8) { ; } } else { var3 = new SecurityManager(); } if (var3 == null) { throw new InternalError("Could not create SecurityManager: " + var2); } System.setSecurityManager(var3); } }
写这么多,其实步骤就这么简单:
一、启动时,将对应bootstrap路径传入,放入System.properties中;
二、初始化路径信息,包括拆解等方式,构建成ClassPathEntry;
三、遍历ClassPathEntry,生成输出流;
四、构建java在c中的数据结构;
需要注意
Java中的loadClass是为了对象化,而c中的loadClass是为了读取成二进制流,职责分离开来!
而大家比较关心的是双亲委派的模式,需要从java端源码入手。
调用方式是:脚本 =》c =》bootstrap =》 java =》Ext =》 App.
双亲委派的 方式就在于java.lang.ClassLoader中:
然后会发现
private native final Class> findLoadedClass0(String name);
调用的是一个native方法!
// Look for a loaded instance or array klass by name. Do not do any loading.
// return NULL in case of error.
klassOop SystemDictionary::find_instance_or_array_klass(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
TRAPS) {
klassOop k = NULL;
assert(class_name != NULL, "class name must be non NULL");
// Try to get one of the well-known klasses.
if (LinkWellKnownClasses) {
k = find_well_known_klass(class_name);
if (k != NULL) {
return k;
}
}
if (FieldType::is_array(class_name)) {
// The name refers to an array. Parse the name.
// dimension and object_key in FieldArrayInfo are assigned as a
// side-effect of this call
FieldArrayInfo fd;
BasicType t = FieldType::get_array_info(class_name, fd, CHECK_(NULL));
if (t != T_OBJECT) {
k = Universe::typeArrayKlassObj(t);
} else {
k = SystemDictionary::find(fd.object_key(), class_loader, protection_domain, THREAD);
}
if (k != NULL) {
k = Klass::cast(k)->array_klass_or_null(fd.dimension());
}
} else {
k = find(class_name, class_loader, protection_domain, THREAD);
}
return k;
}
// This routine does not lock the system dictionary.
//
// Since readers don't hold a lock, we must make sure that system
// dictionary entries are only removed at a safepoint (when only one
// thread is running), and are added to in a safe way (all links must
// be updated in an MT-safe manner).
//
// Callers should be aware that an entry could be added just after
// _dictionary->bucket(index) is read here, so the caller will not see
// the new entry.
klassOop SystemDictionary::find(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
TRAPS) {
// UseNewReflection
// The result of this call should be consistent with the result
// of the call to resolve_instance_class_or_null().
// See evaluation 6790209 and 4474172 for more details.
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
unsigned int d_hash = dictionary()->compute_hash(class_name, class_loader);
int d_index = dictionary()->hash_to_index(d_hash);
{
// Note that we have an entry, and entries can be deleted only during GC,
// so we cannot allow GC to occur while we're holding this entry.
// We're using a No_Safepoint_Verifier to catch any place where we
// might potentially do a GC at all.
// SystemDictionary::do_unloading() asserts that classes are only
// unloaded at a safepoint.
No_Safepoint_Verifier nosafepoint;
return dictionary()->find(d_index, d_hash, class_name, class_loader,
protection_domain, THREAD);
}
}
大体的意思好像是:有个字典的对应关系,根据该字典找到对应类。
实际上双亲委派,就是包括bootstrap启动类加载器外,类似递归方式,一层一层向上查找类是否存在。
这里注意几点:
1、如果一个类是被一个类加载器加载的,那么该类对应的依赖跟引用也是该类加载器加载, 但是注意,虽然不同,但是不同类加载器之间的类相互使用,一定会通过类型检查,因 为c层面上,也是通过类名查找类型的;
2、loadClass中的findLoadedClass查找boot中类,如果没有,则交给parent的子级加载器加载,一层层委托加载;如果一直没有加载到,那么就从类路径中找类,就是所谓的双亲委派;
3、源码中有一段cache代码,意思就是将硬盘中的class文件读取到内存中取。