美文网首页
JVM类加载源码

JVM类加载源码

作者: kevinfuture | 来源:发表于2018-12-15 18:50 被阅读0次
    // 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 <java_home>/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 <java_home>/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.png

    这里注意几点:

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

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

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

    相关文章

      网友评论

          本文标题:JVM类加载源码

          本文链接:https://www.haomeiwen.com/subject/zrnahqtx.html