JVM类加载源码

// 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启动类加载器外,类似递归方式,一层一层向上查找类是否存在。

JVM类加载源码_第1张图片
图片1.png

这里注意几点:

1、如果一个类是被一个类加载器加载的,那么该类对应的依赖跟引用也是该类加载器加载, 但是注意,虽然不同,但是不同类加载器之间的类相互使用,一定会通过类型检查,因 为c层面上,也是通过类名查找类型的;

2、loadClass中的findLoadedClass查找boot中类,如果没有,则交给parent的子级加载器加载,一层层委托加载;如果一直没有加载到,那么就从类路径中找类,就是所谓的双亲委派;

3、源码中有一段cache代码,意思就是将硬盘中的class文件读取到内存中取。

你可能感兴趣的:(JVM类加载源码)