`
lobin
  • 浏览: 425840 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java/JRE/JVM jni实现原理

 
阅读更多

Java中有种特殊的方法,叫native方法,也叫本机方法,这种方法和其他的方法不同在于通过native修饰,并且在定义native方法时不需要实现,其实现交由本机完成。参考https://lobin.iteye.com/blog/629414中的例子。

 

Java JDK中也有大量方法被定义为native方法。

Java JDK中的native方法由JVM实现。JVM在实现这些native方法时比较特殊,这些native实现一部分通过宏JVM_ENTRY,JVM_END来实现,另一部分在\jdk\src\share\native目录下。

 

通过宏JVM_ENTRY,JVM_END实现方式大概是这样的:

JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
... ...
JVM_END

在看这部分代码时,经常看到THREAD,thread这两个线程相关的变量。这需要展开JVM_ENTRY宏才能看到他们的定义。

... ...
JavaThread* thread=JavaThread::thread_from_jni_environment(env); 
... ...
Thread* THREAD = thread;                                           
/* begin of body */

 

 

 

在编写java程序时,也可以定义native的java方法。

 

在开发Java JNI的时候,我们需要使用javah工具为native方法生成本机接口,javah会生成一个C/C++头文

件,头文件中包含没有native方法对应的本机方法函数的声明。

 

生成本机接口如下:

 

 

>javah -jni -d . JniNewTest 

 

以下是生成的本机接口头文件样例:

 

/* DO NOT EDIT THIS FILE - it is machine generated */  

#include <jni.h>  

/* Header for class JniNewTest */  

  

#ifndef _Included_JniNewTest  

#define _Included_JniNewTest  

#ifdef __cplusplus  

extern "C" {  

#endif  

/* 

 * Class:     JniNewTest 

 * Method:    testMethod 

 * Signature: ()V 

 */  

JNIEXPORT void JNICALL Java_JniNewTest_testMethod  

  (JNIEnv *, jobject);  

  

#ifdef __cplusplus  

}  

#endif  

#endif  

 

然后我们会实现这些本机方法函数,编译后链接生成动态链接库。最后在Java中通过loadLibrary加载动态库,这样Java的native方法就可以使用了。在使用之前要确保调用loadLibrary加载动态库。

 

System.loadLibrary("libjnitest");

 

可以看到生成的native本机接口的头文件中的函数定义,至少有两个参数,第一个是一个JNIEnv *的指针类型的参数,它表示Java Runtime运行时环境,它提供了运行时环境相关的接口Java Native Interface, 或者Java Runtime Interface (JRI),由Netscape定义。在C语言环境下,它是一个struct JNINativeInterface_ **的指针的指针结构体, 在C++语言环境下,则是一个struct JNIEnv_*的指针结构体。第二个是几个native句柄。如果native方法是非static方法,该句柄是一个jobject类型的句柄,表示对应java对象的native句柄。如果是static方法,该句柄是一个jclass类型的句柄,表示对应java类的native句柄。

 

 

关于Java Runtime运行时环境提供的运行时环境相关的接口Java Native Interface, 或者Java Runtime Interface (JRI),参考另一篇文章:Java JNI: Java 本机接口, https://lobin.iteye.com/blog/2437928

 

 

 

那么这个运行时环境是怎么初始化的?

 

 

 

在hotspot\src\share\vm\prims\jni.cpp中定义了一个jni_NativeInterface变量,并对结构体中的成员字段进行了初始化。

// Structure containing all jni functions

struct JNINativeInterface_ jni_NativeInterface = {

    NULL,

    NULL,

    NULL,

 

    NULL,

 

    jni_GetVersion,

 

    jni_DefineClass,

    jni_FindClass,

 

    jni_FromReflectedMethod,

    jni_FromReflectedField,

 

    jni_ToReflectedMethod,

 

    jni_GetSuperclass,

    jni_IsAssignableFrom,

 

    jni_ToReflectedField,

 

    jni_Throw,

    jni_ThrowNew,

    jni_ExceptionOccurred,

    jni_ExceptionDescribe,

    jni_ExceptionClear,

    jni_FatalError,

 

    jni_PushLocalFrame,

    jni_PopLocalFrame,

 

    jni_NewGlobalRef,

    jni_DeleteGlobalRef,

    jni_DeleteLocalRef,

    jni_IsSameObject,

 

    jni_NewLocalRef,

    jni_EnsureLocalCapacity,

 

    jni_AllocObject,

    jni_NewObject,

    jni_NewObjectV,

    jni_NewObjectA,

 

    jni_GetObjectClass,

    jni_IsInstanceOf,

 

    jni_GetMethodID,

 

    jni_CallObjectMethod,

    jni_CallObjectMethodV,

    jni_CallObjectMethodA,

    jni_CallBooleanMethod,

    jni_CallBooleanMethodV,

    jni_CallBooleanMethodA,

    jni_CallByteMethod,

    jni_CallByteMethodV,

    jni_CallByteMethodA,

    jni_CallCharMethod,

    jni_CallCharMethodV,

    jni_CallCharMethodA,

    jni_CallShortMethod,

    jni_CallShortMethodV,

    jni_CallShortMethodA,

    jni_CallIntMethod,

    jni_CallIntMethodV,

    jni_CallIntMethodA,

    jni_CallLongMethod,

    jni_CallLongMethodV,

    jni_CallLongMethodA,

    jni_CallFloatMethod,

    jni_CallFloatMethodV,

    jni_CallFloatMethodA,

    jni_CallDoubleMethod,

    jni_CallDoubleMethodV,

    jni_CallDoubleMethodA,

    jni_CallVoidMethod,

    jni_CallVoidMethodV,

    jni_CallVoidMethodA,

 

    jni_CallNonvirtualObjectMethod,

    jni_CallNonvirtualObjectMethodV,

    jni_CallNonvirtualObjectMethodA,

    jni_CallNonvirtualBooleanMethod,

    jni_CallNonvirtualBooleanMethodV,

    jni_CallNonvirtualBooleanMethodA,

    jni_CallNonvirtualByteMethod,

    jni_CallNonvirtualByteMethodV,

    jni_CallNonvirtualByteMethodA,

    jni_CallNonvirtualCharMethod,

    jni_CallNonvirtualCharMethodV,

    jni_CallNonvirtualCharMethodA,

    jni_CallNonvirtualShortMethod,

    jni_CallNonvirtualShortMethodV,

    jni_CallNonvirtualShortMethodA,

    jni_CallNonvirtualIntMethod,

    jni_CallNonvirtualIntMethodV,

    jni_CallNonvirtualIntMethodA,

    jni_CallNonvirtualLongMethod,

    jni_CallNonvirtualLongMethodV,

    jni_CallNonvirtualLongMethodA,

    jni_CallNonvirtualFloatMethod,

    jni_CallNonvirtualFloatMethodV,

    jni_CallNonvirtualFloatMethodA,

    jni_CallNonvirtualDoubleMethod,

    jni_CallNonvirtualDoubleMethodV,

    jni_CallNonvirtualDoubleMethodA,

    jni_CallNonvirtualVoidMethod,

    jni_CallNonvirtualVoidMethodV,

    jni_CallNonvirtualVoidMethodA,

 

    jni_GetFieldID,

 

    jni_GetObjectField,

    jni_GetBooleanField,

    jni_GetByteField,

    jni_GetCharField,

    jni_GetShortField,

    jni_GetIntField,

    jni_GetLongField,

    jni_GetFloatField,

    jni_GetDoubleField,

 

    jni_SetObjectField,

    jni_SetBooleanField,

    jni_SetByteField,

    jni_SetCharField,

    jni_SetShortField,

    jni_SetIntField,

    jni_SetLongField,

    jni_SetFloatField,

    jni_SetDoubleField,

 

    jni_GetStaticMethodID,

 

    jni_CallStaticObjectMethod,

    jni_CallStaticObjectMethodV,

    jni_CallStaticObjectMethodA,

    jni_CallStaticBooleanMethod,

    jni_CallStaticBooleanMethodV,

    jni_CallStaticBooleanMethodA,

    jni_CallStaticByteMethod,

    jni_CallStaticByteMethodV,

    jni_CallStaticByteMethodA,

    jni_CallStaticCharMethod,

    jni_CallStaticCharMethodV,

    jni_CallStaticCharMethodA,

    jni_CallStaticShortMethod,

    jni_CallStaticShortMethodV,

    jni_CallStaticShortMethodA,

    jni_CallStaticIntMethod,

    jni_CallStaticIntMethodV,

    jni_CallStaticIntMethodA,

    jni_CallStaticLongMethod,

    jni_CallStaticLongMethodV,

    jni_CallStaticLongMethodA,

    jni_CallStaticFloatMethod,

    jni_CallStaticFloatMethodV,

    jni_CallStaticFloatMethodA,

    jni_CallStaticDoubleMethod,

    jni_CallStaticDoubleMethodV,

    jni_CallStaticDoubleMethodA,

    jni_CallStaticVoidMethod,

    jni_CallStaticVoidMethodV,

    jni_CallStaticVoidMethodA,

 

    jni_GetStaticFieldID,

 

    jni_GetStaticObjectField,

    jni_GetStaticBooleanField,

    jni_GetStaticByteField,

    jni_GetStaticCharField,

    jni_GetStaticShortField,

    jni_GetStaticIntField,

    jni_GetStaticLongField,

    jni_GetStaticFloatField,

    jni_GetStaticDoubleField,

 

    jni_SetStaticObjectField,

    jni_SetStaticBooleanField,

    jni_SetStaticByteField,

    jni_SetStaticCharField,

    jni_SetStaticShortField,

    jni_SetStaticIntField,

    jni_SetStaticLongField,

    jni_SetStaticFloatField,

    jni_SetStaticDoubleField,

 

    jni_NewString,

    jni_GetStringLength,

    jni_GetStringChars,

    jni_ReleaseStringChars,

 

    jni_NewStringUTF,

    jni_GetStringUTFLength,

    jni_GetStringUTFChars,

    jni_ReleaseStringUTFChars,

 

    jni_GetArrayLength,

 

    jni_NewObjectArray,

    jni_GetObjectArrayElement,

    jni_SetObjectArrayElement,

 

    jni_NewBooleanArray,

    jni_NewByteArray,

    jni_NewCharArray,

    jni_NewShortArray,

    jni_NewIntArray,

    jni_NewLongArray,

    jni_NewFloatArray,

    jni_NewDoubleArray,

 

    jni_GetBooleanArrayElements,

    jni_GetByteArrayElements,

    jni_GetCharArrayElements,

    jni_GetShortArrayElements,

    jni_GetIntArrayElements,

    jni_GetLongArrayElements,

    jni_GetFloatArrayElements,

    jni_GetDoubleArrayElements,

 

    jni_ReleaseBooleanArrayElements,

    jni_ReleaseByteArrayElements,

    jni_ReleaseCharArrayElements,

    jni_ReleaseShortArrayElements,

    jni_ReleaseIntArrayElements,

    jni_ReleaseLongArrayElements,

    jni_ReleaseFloatArrayElements,

    jni_ReleaseDoubleArrayElements,

 

    jni_GetBooleanArrayRegion,

    jni_GetByteArrayRegion,

    jni_GetCharArrayRegion,

    jni_GetShortArrayRegion,

    jni_GetIntArrayRegion,

    jni_GetLongArrayRegion,

    jni_GetFloatArrayRegion,

    jni_GetDoubleArrayRegion,

 

    jni_SetBooleanArrayRegion,

    jni_SetByteArrayRegion,

    jni_SetCharArrayRegion,

    jni_SetShortArrayRegion,

    jni_SetIntArrayRegion,

    jni_SetLongArrayRegion,

    jni_SetFloatArrayRegion,

    jni_SetDoubleArrayRegion,

 

    jni_RegisterNatives,

    jni_UnregisterNatives,

 

    jni_MonitorEnter,

    jni_MonitorExit,

 

    jni_GetJavaVM,

 

    jni_GetStringRegion,

    jni_GetStringUTFRegion,

 

    jni_GetPrimitiveArrayCritical,

    jni_ReleasePrimitiveArrayCritical,

 

    jni_GetStringCritical,

    jni_ReleaseStringCritical,

 

    jni_NewWeakGlobalRef,

    jni_DeleteWeakGlobalRef,

 

    jni_ExceptionCheck,

 

    jni_NewDirectByteBuffer,

    jni_GetDirectBufferAddress,

    jni_GetDirectBufferCapacity,

 

    // New 1_6 features

 

    jni_GetObjectRefType

};

 

同时定义了一个函数jni_functions,该函数通过对应的指针返回jni_NativeInterface变量。

 

// Returns the function structure

struct JNINativeInterface_* jni_functions() {

#ifndef JNICHECK_KERNEL

  if (CheckJNICalls) return jni_functions_check();

#else  // JNICHECK_KERNEL

  if (CheckJNICalls) warning("-Xcheck:jni is not supported in kernel vm.");

#endif // JNICHECK_KERNEL

  return &jni_NativeInterface;

}

 

在构造JavaThread的时候,会调用initialize方法进行初始化,initialize函数通过set_jni_functions函数初始化

 

JNIEnv (即struct JNIEnv_)的_jni_environment成员。

 

 

 

在InitializeJVM初始化Java VM(虚拟机)的时候,在调用InvocationFunctions的CreateJavaVM函数(这里

 

其实是个函数指针,指向JNI_CreateJavaVM函数)时,通过Threads::create_vm创建一个VM(虚拟机),

 

并进行VM初始化,还会为VM创建一个线程(vm线程):

jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {

 

  extern void JDK_Version_init();

 

  // Check version

  if (!is_supported_jni_version(args->version)) return JNI_EVERSION;

 

  // Initialize the output stream module

  ostream_init();

 

  // Process java launcher properties.

  Arguments::process_sun_java_launcher_properties(args);

 

  // Initialize the os module before using TLS

  os::init();

 

  // Initialize system properties.

  Arguments::init_system_properties();

 

  // So that JDK version can be used as a discrimintor when parsing arguments

  JDK_Version_init();

 

  // Update/Initialize System properties after JDK version number is known

  Arguments::init_version_specific_system_properties();

 

  // Parse arguments

  jint parse_result = Arguments::parse(args);

  if (parse_result != JNI_OK) return parse_result;

 

  if (PauseAtStartup) {

    os::pause();

  }

 

#ifndef USDT2

  HS_DTRACE_PROBE(hotspot, vm__init__begin);

#else /* USDT2 */

  HOTSPOT_VM_INIT_BEGIN();

#endif /* USDT2 */

 

  // Record VM creation timing statistics

  TraceVmCreationTime create_vm_timer;

  create_vm_timer.start();

 

  // Timing (must come after argument parsing)

  TraceTime timer("Create VM", TraceStartupTime);

 

  // Initialize the os module after parsing the args

  jint os_init_2_result = os::init_2();

  if (os_init_2_result != JNI_OK) return os_init_2_result;

 

  // Initialize output stream logging

  ostream_init_log();

 

  // Convert -Xrun to -agentlib: if there is no JVM_OnLoad

  // Must be before create_vm_init_agents()

  if (Arguments::init_libraries_at_startup()) {

    convert_vm_init_libraries_to_agents();

  }

 

  // Launch -agentlib/-agentpath and converted -Xrun agents

  if (Arguments::init_agents_at_startup()) {

    create_vm_init_agents();

  }

 

  // Initialize Threads state

  _thread_list = NULL;

  _number_of_threads = 0;

  _number_of_non_daemon_threads = 0;

 

  // Initialize TLS

  ThreadLocalStorage::init();

 

  // Initialize global data structures and create system classes in heap

  vm_init_globals();

 

  // Attach the main thread to this os thread

  JavaThread* main_thread = new JavaThread();

  main_thread->set_thread_state(_thread_in_vm);

  // must do this before set_active_handles and initialize_thread_local_storage

  // Note: on solaris initialize_thread_local_storage() will (indirectly)

  // change the stack size recorded here to one based on the java thread

  // stacksize. This adjusted size is what is used to figure the placement

  // of the guard pages.

  main_thread->record_stack_base_and_size();

  main_thread->initialize_thread_local_storage();

 

  main_thread->set_active_handles(JNIHandleBlock::allocate_block());

 

  if (!main_thread->set_as_starting_thread()) {

    vm_shutdown_during_initialization(

      "Failed necessary internal allocation. Out of swap space");

    delete main_thread;

    *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again

    return JNI_ENOMEM;

  }

 

  // Enable guard page *after* os::create_main_thread(), otherwise it would

  // crash Linux VM, see notes in os_linux.cpp.

  main_thread->create_stack_guard_pages();

 

  // Initialize Java-Level synchronization subsystem

  ObjectMonitor::Initialize() ;

 

  // Initialize global modules

  jint status = init_globals();

  if (status != JNI_OK) {

    delete main_thread;

    *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again

    return status;

  }

 

  // Should be done after the heap is fully created

  main_thread->cache_global_variables();

 

  HandleMark hm;

 

  { MutexLocker mu(Threads_lock);

    Threads::add(main_thread);

  }

 

  // Any JVMTI raw monitors entered in onload will transition into

  // real raw monitor. VM is setup enough here for raw monitor enter.

  JvmtiExport::transition_pending_onload_raw_monitors();

 

  if (VerifyBeforeGC &&

      Universe::heap()->total_collections() >= VerifyGCStartAt) {

    Universe::heap()->prepare_for_verify();

    Universe::verify();   // make sure we're starting with a clean slate

  }

 

  // Create the VMThread

  { TraceTime timer("Start VMThread", TraceStartupTime);

    VMThread::create();

    Thread* vmthread = VMThread::vm_thread();

 

    if (!os::create_thread(vmthread, os::vm_thread))

      vm_exit_during_initialization("Cannot create VM thread. Out of system resources.");

 

    // Wait for the VM thread to become ready, and VMThread::run to initialize

    // Monitors can have spurious returns, must always check another state flag

    {

      MutexLocker ml(Notify_lock);

      os::start_thread(vmthread);

      while (vmthread->active_handles() == NULL) {

        Notify_lock->wait();

      }

    }

  }

 

  assert (Universe::is_fully_initialized(), "not initialized");

  EXCEPTION_MARK;

 

  // At this point, the Universe is initialized, but we have not executed

  // any byte code.  Now is a good time (the only time) to dump out the

  // internal state of the JVM for sharing.

 

  if (DumpSharedSpaces) {

    Universe::heap()->preload_and_dump(CHECK_0);

    ShouldNotReachHere();

  }

 

  // Always call even when there are not JVMTI environments yet, since environments

  // may be attached late and JVMTI must track phases of VM execution

  JvmtiExport::enter_start_phase();

 

  // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents.

  JvmtiExport::post_vm_start();

 

  {

    TraceTime timer("Initialize java.lang classes", TraceStartupTime);

 

    if (EagerXrunInit && Arguments::init_libraries_at_startup()) {

      create_vm_init_libraries();

    }

 

    if (InitializeJavaLangString) {

      initialize_class(vmSymbols::java_lang_String(), CHECK_0);

    } else {

      warning("java.lang.String not initialized");

    }

 

    if (AggressiveOpts) {

      {

        // Forcibly initialize java/util/HashMap and mutate the private

        // static final "frontCacheEnabled" field before we start creating instances

#ifdef ASSERT

        klassOop tmp_k = SystemDictionary::find(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);

        assert(tmp_k == NULL, "java/util/HashMap should not be loaded yet");

#endif

        klassOop k_o = SystemDictionary::resolve_or_null(vmSymbols::java_util_HashMap(), Handle(), Handle(), CHECK_0);

        KlassHandle k = KlassHandle(THREAD, k_o);

        guarantee(k.not_null(), "Must find java/util/HashMap");

        instanceKlassHandle ik = instanceKlassHandle(THREAD, k());

        ik->initialize(CHECK_0);

        fieldDescriptor fd;

        // Possible we might not find this field; if so, don't break

        if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) {

          k()->java_mirror()->bool_field_put(fd.offset(), true);

        }

      }

 

      if (UseStringCache) {

        // Forcibly initialize java/lang/StringValue and mutate the private

        // static final "stringCacheEnabled" field before we start creating instances

        klassOop k_o = SystemDictionary::resolve_or_null(vmSymbols::java_lang_StringValue(), Handle(), Handle(), CHECK_0);

        // Possible that StringValue isn't present: if so, silently don't break

        if (k_o != NULL) {

          KlassHandle k = KlassHandle(THREAD, k_o);

          instanceKlassHandle ik = instanceKlassHandle(THREAD, k());

          ik->initialize(CHECK_0);

          fieldDescriptor fd;

          // Possible we might not find this field: if so, silently don't break

          if (ik->find_local_field(vmSymbols::stringCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) {

            k()->java_mirror()->bool_field_put(fd.offset(), true);

          }

        }

      }

    }

 

    // Initialize java_lang.System (needed before creating the thread)

    if (InitializeJavaLangSystem) {

      initialize_class(vmSymbols::java_lang_System(), CHECK_0);

      initialize_class(vmSymbols::java_lang_ThreadGroup(), CHECK_0);

      Handle thread_group = create_initial_thread_group(CHECK_0);

      Universe::set_main_thread_group(thread_group());

      initialize_class(vmSymbols::java_lang_Thread(), CHECK_0);

      oop thread_object = create_initial_thread(thread_group, main_thread, CHECK_0);

      main_thread->set_threadObj(thread_object);

      // Set thread status to running since main thread has

      // been started and running.

      java_lang_Thread::set_thread_status(thread_object,

                                          java_lang_Thread::RUNNABLE);

 

      // The VM preresolve methods to these classes. Make sure that get initialized

      initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK_0);

      initialize_class(vmSymbols::java_lang_ref_Finalizer(),  CHECK_0);

      // The VM creates & returns objects of this class. Make sure it's initialized.

      initialize_class(vmSymbols::java_lang_Class(), CHECK_0);

      call_initializeSystemClass(CHECK_0);

    } else {

      warning("java.lang.System not initialized");

    }

 

    // an instance of OutOfMemory exception has been allocated earlier

    if (InitializeJavaLangExceptionsErrors) {

      initialize_class(vmSymbols::java_lang_OutOfMemoryError(), CHECK_0);

      initialize_class(vmSymbols::java_lang_NullPointerException(), CHECK_0);

      initialize_class(vmSymbols::java_lang_ClassCastException(), CHECK_0);

      initialize_class(vmSymbols::java_lang_ArrayStoreException(), CHECK_0);

      initialize_class(vmSymbols::java_lang_ArithmeticException(), CHECK_0);

      initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK_0);

      initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK_0);

      initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK_0);

    } else {

      warning("java.lang.OutOfMemoryError has not been initialized");

      warning("java.lang.NullPointerException has not been initialized");

      warning("java.lang.ClassCastException has not been initialized");

      warning("java.lang.ArrayStoreException has not been initialized");

      warning("java.lang.ArithmeticException has not been initialized");

      warning("java.lang.StackOverflowError has not been initialized");

      warning("java.lang.IllegalArgumentException has not been initialized");

    }

  }

 

  // See        : bugid 4211085.

  // Background : the static initializer of java.lang.Compiler tries to read

  //              property"java.compiler" and read & write property "java.vm.info".

  //              When a security manager is installed through the command line

  //              option "-Djava.security.manager", the above properties are not

  //              readable and the static initializer for java.lang.Compiler fails

  //              resulting in a NoClassDefFoundError.  This can happen in any

  //              user code which calls methods in java.lang.Compiler.

  // Hack :       the hack is to pre-load and initialize this class, so that only

  //              system domains are on the stack when the properties are read.

  //              Currently even the AWT code has calls to methods in java.lang.Compiler.

  //              On the classic VM, java.lang.Compiler is loaded very early to load the JIT.

  // Future Fix : the best fix is to grant everyone permissions to read "java.compiler" and

  //              read and write"java.vm.info" in the default policy file. See bugid 4211383

  //              Once that is done, we should remove this hack.

  initialize_class(vmSymbols::java_lang_Compiler(), CHECK_0);

 

  // More hackery - the static initializer of java.lang.Compiler adds the string "nojit" to

  // the java.vm.info property if no jit gets loaded through java.lang.Compiler (the hotspot

  // compiler does not get loaded through java.lang.Compiler).  "java -version" with the

  // hotspot vm says "nojit" all the time which is confusing.  So, we reset it here.

  // This should also be taken out as soon as 4211383 gets fixed.

  reset_vm_info_property(CHECK_0);

 

  quicken_jni_functions();

 

  // Must be run after init_ft which initializes ft_enabled

  if (TRACE_INITIALIZE() != JNI_OK) {

    vm_exit_during_initialization("Failed to initialize tracing backend");

  }

 

  // Set flag that basic initialization has completed. Used by exceptions and various

  // debug stuff, that does not work until all basic classes have been initialized.

  set_init_completed();

 

#ifndef USDT2

  HS_DTRACE_PROBE(hotspot, vm__init__end);

#else /* USDT2 */

  HOTSPOT_VM_INIT_END();

#endif /* USDT2 */

 

  // record VM initialization completion time

  Management::record_vm_init_completed();

 

  // Compute system loader. Note that this has to occur after set_init_completed, since

  // valid exceptions may be thrown in the process.

  // Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and

  // set_init_completed has just been called, causing exceptions not to be shortcut

  // anymore. We call vm_exit_during_initialization directly instead.

  SystemDictionary::compute_java_system_loader(THREAD);

  if (HAS_PENDING_EXCEPTION) {

    vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));

  }

 

#ifndef SERIALGC

  // Support for ConcurrentMarkSweep. This should be cleaned up

  // and better encapsulated. The ugly nested if test would go away

  // once things are properly refactored. XXX YSR

  if (UseConcMarkSweepGC || UseG1GC) {

    if (UseConcMarkSweepGC) {

      ConcurrentMarkSweepThread::makeSurrogateLockerThread(THREAD);

    } else {

      ConcurrentMarkThread::makeSurrogateLockerThread(THREAD);

    }

    if (HAS_PENDING_EXCEPTION) {

      vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));

    }

  }

#endif // SERIALGC

 

  // Always call even when there are not JVMTI environments yet, since environments

  // may be attached late and JVMTI must track phases of VM execution

  JvmtiExport::enter_live_phase();

 

  // Signal Dispatcher needs to be started before VMInit event is posted

  os::signal_init();

 

  // Start Attach Listener if +StartAttachListener or it can't be started lazily

  if (!DisableAttachMechanism) {

    if (StartAttachListener || AttachListener::init_at_startup()) {

      AttachListener::init();

    }

  }

 

  // Launch -Xrun agents

  // Must be done in the JVMTI live phase so that for backward compatibility the JDWP

  // back-end can launch with -Xdebug -Xrunjdwp.

  if (!EagerXrunInit && Arguments::init_libraries_at_startup()) {

    create_vm_init_libraries();

  }

 

  if (!TRACE_START()) {

    vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));

  }

 

  // Notify JVMTI agents that VM initialization is complete - nop if no agents.

  JvmtiExport::post_vm_initialized();

 

  if (CleanChunkPoolAsync) {

    Chunk::start_chunk_pool_cleaner_task();

  }

 

  // initialize compiler(s)

  CompileBroker::compilation_init();

 

  Management::initialize(THREAD);

  if (HAS_PENDING_EXCEPTION) {

    // management agent fails to start possibly due to

    // configuration problem and is responsible for printing

    // stack trace if appropriate. Simply exit VM.

    vm_exit(1);

  }

 

  if (Arguments::has_profile())       FlatProfiler::engage(main_thread, true);

  if (Arguments::has_alloc_profile()) AllocationProfiler::engage();

  if (MemProfiling)                   MemProfiler::engage();

  StatSampler::engage();

  if (CheckJNICalls)                  JniPeriodicChecker::engage();

 

  BiasedLocking::init();

 

  if (JDK_Version::current().post_vm_init_hook_enabled()) {

    call_postVMInitHook(THREAD);

    // The Java side of PostVMInitHook.run must deal with all

    // exceptions and provide means of diagnosis.

    if (HAS_PENDING_EXCEPTION) {

      CLEAR_PENDING_EXCEPTION;

    }

  }

 

  // Start up the WatcherThread if there are any periodic tasks

  // NOTE:  All PeriodicTasks should be registered by now. If they

  //   aren't, late joiners might appear to start slowly (we might

  //   take a while to process their first tick).

  if (PeriodicTask::num_tasks() > 0) {

    WatcherThread::start();

  }

 

  // Give os specific code one last chance to start

  os::init_3();

 

  create_vm_timer.end();

  return JNI_OK;

}

为VM创建一个线程(vm线程)的代码:

  // Create the VMThread

  { TraceTime timer("Start VMThread", TraceStartupTime);

    VMThread::create();

    Thread* vmthread = VMThread::vm_thread();

 

    if (!os::create_thread(vmthread, os::vm_thread))

      vm_exit_during_initialization("Cannot create VM thread. Out of system resources.");

 

    // Wait for the VM thread to become ready, and VMThread::run to initialize

    // Monitors can have spurious returns, must always check another state flag

    {

      MutexLocker ml(Notify_lock);

      os::start_thread(vmthread);

      while (vmthread->active_handles() == NULL) {

        Notify_lock->wait();

      }

    }

  }

同时还会创建一个主线程,代码如下:

  // Attach the main thread to this os thread

  JavaThread* main_thread = new JavaThread();

  main_thread->set_thread_state(_thread_in_vm);

  // must do this before set_active_handles and initialize_thread_local_storage

  // Note: on solaris initialize_thread_local_storage() will (indirectly)

  // change the stack size recorded here to one based on the java thread

  // stacksize. This adjusted size is what is used to figure the placement

  // of the guard pages.

  main_thread->record_stack_base_and_size();

  main_thread->initialize_thread_local_storage();

Java VM(虚拟机)创建后,从对应的主线程中得到这个运行时环境。

 

这个运行时环境就是这么来的。。。

 

 

以structJNINativeInterface_的FindClass为例

 

jclass (JNICALL *FindClass)      (JNIEnv *env, const char *name);

 

在jni.cpp中可以看出对应的函数实现为jni_FindClass

 

jni_FindClass对应的实现:

 

 

 

 

jni_FindClass对应的实现

 

 

static bool first_time_FindClass = true;

 

#ifndef USDT2

DT_RETURN_MARK_DECL(FindClass, jclass);

#else /* USDT2 */

DT_RETURN_MARK_DECL(FindClass, jclass

                    , HOTSPOT_JNI_FINDCLASS_RETURN(_ret_ref));

#endif /* USDT2 */

 

JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name))

  JNIWrapper("FindClass");

#ifndef USDT2

  DTRACE_PROBE2(hotspot_jni, FindClass__entry, env, name);

#else /* USDT2 */

  HOTSPOT_JNI_FINDCLASS_ENTRY(

                              env, (char *)name);

#endif /* USDT2 */

 

  jclass result = NULL;

  DT_RETURN_MARK(FindClass, jclass, (const jclass&)result);

 

  // Remember if we are the first invocation of jni_FindClass

  bool first_time = first_time_FindClass;

  first_time_FindClass = false;

 

  // Sanity check the name:  it cannot be null or larger than the maximum size

  // name we can fit in the constant pool.

  if (name == NULL || (int)strlen(name) > Symbol::max_length()) {

    THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), name);

  }

 

  //%note jni_3

  Handle loader;

  Handle protection_domain;

  // Find calling class

  instanceKlassHandle k (THREAD, thread->security_get_caller_class(0));

  if (k.not_null()) {

    loader = Handle(THREAD, k->class_loader());

    // Special handling to make sure JNI_OnLoad and JNI_OnUnload are executed

    // in the correct class context.

    if (loader.is_null() &&

        k->name() == vmSymbols::java_lang_ClassLoader_NativeLibrary()) {

      JavaValue result(T_OBJECT);

      JavaCalls::call_static(&result, k,

                                      vmSymbols::getFromClass_name(),

                                      vmSymbols::void_class_signature(),

                                      thread);

      if (HAS_PENDING_EXCEPTION) {

        Handle ex(thread, thread->pending_exception());

        CLEAR_PENDING_EXCEPTION;

        THROW_HANDLE_0(ex);

      }

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

      loader = Handle(THREAD,

        instanceKlass::cast(java_lang_Class::as_klassOop(mirror))->class_loader());

      protection_domain = Handle(THREAD,

        instanceKlass::cast(java_lang_Class::as_klassOop(mirror))->protection_domain());

    }

  } else {

    // We call ClassLoader.getSystemClassLoader to obtain the system class loader.

    loader = Handle(THREAD, SystemDictionary::java_system_loader());

  }

 

  TempNewSymbol sym = SymbolTable::new_symbol(name, CHECK_NULL);

  result = find_class_from_class_loader(env, sym, true, loader,

                                        protection_domain, true, thread);

 

  if (TraceClassResolution && result != NULL) {

    trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));

  }

 

  // If we were the first invocation of jni_FindClass, we enable compilation again

  // rather than just allowing invocation counter to overflow and decay.

  // Controlled by flag DelayCompilationDuringStartup.

  if (first_time && !CompileTheWorld)

    CompilationPolicy::completed_vm_startup();

 

  return result;

 

JNI_END

 

 

 

 

 

分解后

 

 

 

static bool first_time_FindClass = true;

 

#ifndef USDT2

 

#else /* USDT2 */

 

#endif /* USDT2 */

 

extern "C" {                                                         

  jclass JNICALL jni_FindClass(JNIEnv *env, const char *name) {                                

    JavaThread* thread=JavaThread::thread_from_jni_environment(env); 

    assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); 

    ThreadInVMfromNative __tiv(thread);                              

    debug_only(VMNativeEntryWrapper __vew;)                          

    VM_ENTRY_BASE(jclass, jni_FindClass(JNIEnv *env, const char *name), thread)                 

WeakPreserveExceptionMark __wem(thread);

 

JNIWrapper("FindClass");

#ifndef USDT2

{;}

;

#else /* USDT2 */

;

#endif /* USDT2 */

 

jclass result = NULL;

 

// Remember if we are the first invocation of jni_FindClass

bool first_time = first_time_FindClass;

first_time_FindClass = false;

 

// Sanity check the name:  it cannot be null or larger than the maximum size

// name we can fit in the constant pool.

if (name == NULL || (int)strlen(name) > Symbol::max_length()) {

 { 

   Exceptions::_throw_msg(THREAD_AND_LOCATION, vmSymbols::java_lang_NoClassDefFoundError(), name); 

   return result; 

 }

 ;

    }

 

//%note jni_3

Handle loader;

Handle protection_domain;

// Find calling class

instanceKlassHandle k (THREAD, thread->security_get_caller_class(0));

if (k.not_null()) {

 loader = Handle(THREAD, k->class_loader());

 // Special handling to make sure JNI_OnLoad and JNI_OnUnload are executed

 // in the correct class context.

      if (loader.is_null() &&

        k->name() == vmSymbols::java_lang_ClassLoader_NativeLibrary()) {

        JavaValue result(T_OBJECT);

        JavaCalls::call_static(&result, k,

                                      vmSymbols::getFromClass_name(),

                                      vmSymbols::void_class_signature(),

                                      thread);

        if (HAS_PENDING_EXCEPTION) {

          Handle ex(thread, thread->pending_exception());

          CLEAR_PENDING_EXCEPTION;

          THROW_HANDLE_0(ex);

        }

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

        loader = Handle(THREAD,

          instanceKlass::cast(java_lang_Class::as_klassOop(mirror))->class_loader());

        protection_domain = Handle(THREAD,

          instanceKlass::cast(java_lang_Class::as_klassOop(mirror))->protection_domain());

      }

} else {

      // We call ClassLoader.getSystemClassLoader to obtain the system class loader.

      loader = Handle(THREAD, SystemDictionary::java_system_loader());

    }

 

TempNewSymbol sym = SymbolTable::new_symbol(name, CHECK_NULL);

result = find_class_from_class_loader(env, sym, true, loader,

                                        protection_domain, true, thread);

 

if (TraceClassResolution && result != NULL) {

      trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));

}

 

    // If we were the first invocation of jni_FindClass, we enable compilation again

// rather than just allowing invocation counter to overflow and decay.

// Controlled by flag DelayCompilationDuringStartup.

if (first_time && !CompileTheWorld)

      CompilationPolicy::completed_vm_startup();

 

return result;

  } 

 

}

 

 

那么动态链接库是怎么加载的?除了我们自行开发的动态链接库,Java JDK内部也有很多native方法,对应在Java运行时环境JRE中也有对应的动态库。

 

 

还有这些动态库是怎么注册的?

 

Java native方法是怎么和本机方法实现绑定的?

 

在调用Java native方法时是怎么lookup对应的实现的?

 

 

 

Java在运行时实时编译时,如果编译的方法是个native方法,调用NativeLookup::lookup查找native方法的实现。

 

这在CompileBroker::compile_method中会调用NativeLookup::lookup查找native方法的实现。参考hotspot\src\share\vm\compiler\compileBroker.cpp的compile_method方法实现。另外

分享到:
评论

相关推荐

    hsdis-amd64.dll,放在<JAVA-HOME>/jre/bin目录下

    将hsdis-amd64.dll放置在&lt;JAVA-HOME&gt;/jre/bin目录下,是因为这是JVM查找附加组件的默认路径之一。 Java HotSpot虚拟机是Oracle JDK和OpenJDK实现的一个版本,它具有即时编译(JIT,Just-In-Time)的功能。JIT编译器...

    JDK/JRE 11.0.18

    它包含JRE,后者是运行Java应用程序所必需的环境,包括Java虚拟机(JVM)、Java类库以及相关的配置文件和工具。JDK 11.0.18作为长期支持(LTS)版本,意味着它会得到更长时间的安全性和功能更新,这对于企业级应用来...

    JRE--Java程序,Java语言编写的软件运行环境

    此外,JRE还包括Java Native Interface (JNI),允许Java代码调用本地操作系统提供的函数,实现与硬件的低级别交互。 在给定的文件"jre-6u21-windows-i586-s.exe"中,我们可以看出这是一款针对Windows操作系统且适用...

    java调c示例,JNI的使用

    g++ -shared -o libnative-lib.so -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux NativeDemo.cpp ``` 5. **测试和运行**:最后,我们可以在Java程序中调用这些...

    Windows 下 JNI 备忘

    它允许Java代码和其他语言编写的代码进行交互,从而可以调用在Java虚拟机(JVM)外部实现的本地应用程序接口(API)和库函数。本文将详细介绍如何在Windows环境下使用JNI进行编程,并会列出相关的知识点和步骤。 1....

    超级精简版jre(只用10M)

    Java运行环境(JRE,Java Runtime Environment)是执行Java应用程序所必需的基础软件,它包含了Java虚拟机(JVM,Java Virtual Machine)以及Java类库。标题提到的“超级精简版jre”,顾名思义,是针对常规JRE进行...

    javaVM jre-1_5_0_06

    - **本地接口和JNI(Java Native Interface)**:允许Java代码调用本地操作系统API,实现与系统底层交互。 3. **JRE-1_5_0_06的具体改进**: - 性能优化:对JVM进行了性能调整,提高了代码执行效率。 - 安全性...

    java8看不到源码-beethefirst-software:beethefirst-软件

    java8 看不到源码beethefirst-软件 开发发生在此处的“开发”分支.../usr/lib/jvm/java-8-oracle/jre/lib/ext/ sudo apt-get install libjava3d-jni sudo cp /usr/lib/jni/libj3dcore-ogl.so /usr/lib/jvm/java-8-orac

    java_jre15已集成JavaFX16

    JRE(Java Runtime Environment)是运行Java应用程序所必需的环境,它包含了Java虚拟机(JVM)、类库以及其他支持Java程序运行的组件。在Java 15.0.2中集成JavaFX 16,意味着用户不再需要单独下载和管理JavaFX库,...

    mac 下jni编译代码

    cc -shared -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/darwin -o libMyClass.jnilib MyClass.c ``` 这里,`-I`选项指定了JDK的头文件路径,`-shared`表示我们要...

    java运行环境jre-6u17-windows-i586-s

    JRE使得开发者编写的Java程序能够在任何安装了相应版本JRE的计算机上运行,实现了“一次编写,到处运行”的跨平台特性。在这个场景中,我们讨论的是JRE的6u17版本,专门针对Windows操作系统32位(i586)架构的版本。...

    JAVA 运行环境 jre-8u261-windows-x64.exe

    Java运行环境,通常被称为Java Runtime Environment (JRE),是运行基于Java语言开发的应用程序所必需的基础组件。在本例中,我们关注的是JRE的特定版本——"jre-8u261-windows-x64.exe",这是一个适用于Windows 64位...

    SAP JVM 8.1 64 bits

    SAP JVM 8.1 64位是一个专为SAP系统设计的Java虚拟机,它基于Oracle的Java Development Kit (JDK) 进行优化,以满足SAP应用程序的特定需求。SAP JVM旨在提高性能、可靠性和安全性,同时确保与SAP产品的无缝集成。...

    在c程序中启动Java虚拟机.doc

    const char szJvmPath[] = "D://Program Files//Java/jdk1.6.0_30/jre/bin//server//jvm.dll"; // 加载动态库 HINSTANCE hDll = LoadLibraryA(szJvmPath); if (!hDll) { printf("Failed to load library.\n")...

    delphi调用Java函数

    这通常通过调用`JNI_CreateJavaVM`函数完成,你需要提供JVM的配置参数,如JRE路径等。 4. **加载Java类和调用函数**:一旦JVM注册成功,你可以使用JNI函数`FindClass`找到你的Java类,然后使用`GetStaticMethodID`...

    Java虚拟机(JVM)面试题 51道.pdf

    Java虚拟机(JVM)是Java程序的核心组成部分,它为Java提供了一个跨平台的运行环境。...理解并掌握JVM的工作原理和优化技巧,对Java开发者来说至关重要,它能帮助开发者编写出更高效、更稳定的代码。

    深入Java虚拟机_002_深入详解JVM之类加载器深度剖析、根、扩展及系统类加载器

    根类加载器,也称为bootstrap class loader,是JVM内置的最基础的类加载器,由C++实现,负责加载JDK核心库,如rt.jar,这些库位于JRE的lib目录下,包含了Java的基础类和API。 扩展类加载器,又叫extension class ...

    将Java代码打包为exe文件

    本地代码通常使用C或C++编写,其主要功能是加载JVM,通过JNI(Java Native Interface)接口调用Java代码。这里给出一个示例代码: ```c++ #include #include &lt;jni.h&gt; // JNI动态链接库加载器类型定义 typedef j...

    openjdk 18 linux版本 解压安装包

    - Linux系统中可以通过`update-alternatives`命令管理多个JDK版本,选择默认版本,如`sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk-18/bin/java 1`。 了解这些知识点后,你就可以在...

Global site tag (gtag.js) - Google Analytics