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目录下,是因为这是JVM查找附加组件的默认路径之一。 Java HotSpot虚拟机是Oracle JDK和OpenJDK实现的一个版本,它具有即时编译(JIT,Just-In-Time)的功能。JIT编译器...
它包含JRE,后者是运行Java应用程序所必需的环境,包括Java虚拟机(JVM)、Java类库以及相关的配置文件和工具。JDK 11.0.18作为长期支持(LTS)版本,意味着它会得到更长时间的安全性和功能更新,这对于企业级应用来...
此外,JRE还包括Java Native Interface (JNI),允许Java代码调用本地操作系统提供的函数,实现与硬件的低级别交互。 在给定的文件"jre-6u21-windows-i586-s.exe"中,我们可以看出这是一款针对Windows操作系统且适用...
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程序中调用这些...
它允许Java代码和其他语言编写的代码进行交互,从而可以调用在Java虚拟机(JVM)外部实现的本地应用程序接口(API)和库函数。本文将详细介绍如何在Windows环境下使用JNI进行编程,并会列出相关的知识点和步骤。 1....
Java运行环境(JRE,Java Runtime Environment)是执行Java应用程序所必需的基础软件,它包含了Java虚拟机(JVM,Java Virtual Machine)以及Java类库。标题提到的“超级精简版jre”,顾名思义,是针对常规JRE进行...
- **本地接口和JNI(Java Native Interface)**:允许Java代码调用本地操作系统API,实现与系统底层交互。 3. **JRE-1_5_0_06的具体改进**: - 性能优化:对JVM进行了性能调整,提高了代码执行效率。 - 安全性...
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
JRE(Java Runtime Environment)是运行Java应用程序所必需的环境,它包含了Java虚拟机(JVM)、类库以及其他支持Java程序运行的组件。在Java 15.0.2中集成JavaFX 16,意味着用户不再需要单独下载和管理JavaFX库,...
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`表示我们要...
JRE使得开发者编写的Java程序能够在任何安装了相应版本JRE的计算机上运行,实现了“一次编写,到处运行”的跨平台特性。在这个场景中,我们讨论的是JRE的6u17版本,专门针对Windows操作系统32位(i586)架构的版本。...
Java运行环境,通常被称为Java Runtime Environment (JRE),是运行基于Java语言开发的应用程序所必需的基础组件。在本例中,我们关注的是JRE的特定版本——"jre-8u261-windows-x64.exe",这是一个适用于Windows 64位...
SAP JVM 8.1 64位是一个专为SAP系统设计的Java虚拟机,它基于Oracle的Java Development Kit (JDK) 进行优化,以满足SAP应用程序的特定需求。SAP JVM旨在提高性能、可靠性和安全性,同时确保与SAP产品的无缝集成。...
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")...
这通常通过调用`JNI_CreateJavaVM`函数完成,你需要提供JVM的配置参数,如JRE路径等。 4. **加载Java类和调用函数**:一旦JVM注册成功,你可以使用JNI函数`FindClass`找到你的Java类,然后使用`GetStaticMethodID`...
Java虚拟机(JVM)是Java程序的核心组成部分,它为Java提供了一个跨平台的运行环境。...理解并掌握JVM的工作原理和优化技巧,对Java开发者来说至关重要,它能帮助开发者编写出更高效、更稳定的代码。
根类加载器,也称为bootstrap class loader,是JVM内置的最基础的类加载器,由C++实现,负责加载JDK核心库,如rt.jar,这些库位于JRE的lib目录下,包含了Java的基础类和API。 扩展类加载器,又叫extension class ...
本地代码通常使用C或C++编写,其主要功能是加载JVM,通过JNI(Java Native Interface)接口调用Java代码。这里给出一个示例代码: ```c++ #include #include <jni.h> // JNI动态链接库加载器类型定义 typedef j...
- Linux系统中可以通过`update-alternatives`命令管理多个JDK版本,选择默认版本,如`sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk-18/bin/java 1`。 了解这些知识点后,你就可以在...