출처 :http://www.hp.com/products1/unix/java/infolibrary/prog_guide/JNI_java2.html
Unless specified otherwise, the information in this chapter applies to both HP-UXPA-RISCand
HP-UX Itanium® Processor Family systems. Regarding the examples contained in this chapter, do not use +D64 with Java 1.3 based releases on Itanium. Beginning withSDK1.4.1 you may use +D64.
Table of contents | ||
» | Using Java 2 JNI on HP-UX | |
» | Support for C++ applications built with -AA options (PA-RISC) | |
» | DereferencingNULLpointers | |
» | Using Native Methods on HP-UX | |
» | Java calling a native (non-Java) method | |
» | Sample code for SDK 1.3.1 | |
» | Sample Java calling native method implementation in C | |
» | Sample Java calling native method implementation in HP aC++ | |
» | Native (non-Java) calling Java methods |
» | Sample code for SDK 1.3.1 | |
» | Sample native calling Java implementation in C | |
» | Sample native calling Java implementation in HP aC++ | |
The Java Native Interface, typically referred to as JNI, is a standard native method interface that allows Java to call up native libraries written in other languages. It also allows you to load theJVMinto native applications to integrate Java functionality into native applications. JNI offers a JVM-independent programming interface to native programs which enables developers to write a single native method library version that will be binary compatible with all JVMs on a given platform.
For native code support, the native library must be inSHLIB_PATH. HP suggests that you place your native libraries in
<applicationdirectory>/lib/<architecturedirectory>
When developing applications, if you are using native methods, you must compile them into a shareable native library, for example:
<applicationdirectory>/lib/<architecturedirectory>native_threads/foo.sl
The script that invokes the runtime interpreter for your executable should reset the CLASSPATH and JAVA_HOME environment variables to avoid any conflicts with other Java applications or Java runtime versions on your system. You must also include an installer.
The HP-UX implementation of JNI does not differ significantly from that of the JavaSoft implementation on Solaris. Refer to JavaSoft's JNI documentation listings at:http://onesearch.sun.com/search/developers/index.jsp?qt=JNI&uid=6910018
Support for C++ applications built with-AAand-APoptions (PA-RISC)
Java supports the-AAand-APoptions to build your C++ product. On Itanium systems, the C++ runtime libraries support-AAand-APby default. On HP-UX 11.0 or 11.11 PA-RISC, if you are using the ANSI Standard C++ runtime (-AA) option in an application that loads Java, you need to use the-AAversion oflibjvmandlibfontmanager. Note that these libraries are provided as a separate download on the same page from where you download the SDK and RTE, starting at this webpage:
http://www.hp.com/products1/unix/java/java2/sdkrte14/index.html
These are the Standard C++ Runtime version of these libraries:
./jre/lib/PA_RISC2.0/libjvm_v2.sl
./jre/lib/PA_RISC2.0W/libjvm_v2.sl
./jre/lib/PA_RISC2.0/libfontmanager_v2.sl
./jre/lib/PA_RISC2.0W/libfontmanager_v2.sl
The native application must be linked with, or must dynamically load these versions of the Java libraries if your C++ application is compiled using-AA.
The Standard C++ version of the JVM libraries are supported forPA_RISC2.0andPA_RISC2.0Warchitectures only.
If the JVM is invoked through the standard Java driver, then use the-V2option to use the Standard C++ runtime.
For example:
java -V2 <javaprog>
With the Java 2 HotSpot VM, JNI that incorrectly dereferencesNULLwill result in aSIGSEGV,and JavaNULLchecks can be performed without having to emit explicit to do so. (This is different than the Java 1.1 behavior.) With Java 2 HotSpot, the signal is caught, and a null pointer exception is thrown if the offending instruction was within the VM (compiled, or in the interpreter). This method may uncover hidden programming errors.
Also, if you are including the HP-UX Runtime Environment for the Java 2 Platform in an application and bypassing our standard driver, for example by making calls toJNI_CreateJavaVMfrom inside the application, link the application with the "-z" option. The-zoption will indicate that dereferencingNULLpointers in the application should generate aSIGSEGVinstead of the traditional behavior of returning zero. If you do not, you will not be able to take advantage of implicit null pointer checks; null pointer checks will have to be explicit, potentially degrading performance. Linking with-zmay also expose existing but quiet bugs in an application. This is because theSIGSEGVswere not being generated before.
The sections below detail the differences that you need to be aware of when using native methods on HP-UX. Examples are provided for Java 1.3 and 1.4 that illustrate the capabilities for implementation in C and C++.
Note:The default stack size for 1.4 and 5.0 64-bit mode threads created by the JVM is 1MB. On PA-RISC 32 and 64-bit systems, the default stack size is 64KB. Therefore, if you are using C language main programs that attach with JNI, for threads created using the pthread library, you will want to adjust the stack size to avoid overflows. For further details on thread Stack Size Limits, refer to "Main/primordial thread stack size limits" and "Non-Main/primordial thread stack size limits".
Java calling a native (non-Java) method
The first capability that JNI provides is to allow Java running under the Java Virtual Machine (JVM) to make native method calls. This allows the Java programmer to supply a native implementation instead of a Java implementation for any method in any user defined class. The Java keywordnativeis used in the declaration of the method and no body or definition is supplied in the Java source.
native void sample(int x, int y);
The above declares a non-static native method named "sample" which returns a void and it accepts two integers as parameters.
The native method must be implemented in C or C++. When using C++ native methods special care must be taken to properly initialize the C++ runtime before transferring control to any C++ native method. For the HP C++ compiler this means that the routine_mainmust be called before transferring control to any C++ method. The examples below detail a mechanism for ensuring that the C++ runtime is properly initialized.
All Java native methods must reside in a shared library. This implies that the native methods must be built using the+zor+Zcompiler options. These options cause the compiler to generatePIC(Position-Independent-Code). The shared library containing the native method implementation is dynamically loaded during execution of the Java program using the Java method:
System.loadLibrary(). The implementation of this function with the JVM on HP-UX relies upon the HP-UX runtime routineshl_load.
The alignment requirements for Java data structures allocated in the JVM are not the same as those found in the standard PA-RISC 2.0 calling conventions. The JVM requires that class instance data members 64-bits in size (longs and doubles) be allocated at the next available 4-byte boundary. The standard PA-RISC 2.0 calling conventions normally require that such objects be aligned on the next 8-byte boundary. If a C or C++ native method were to access such a Java class instance data member that was not properly aligned on an 8-byte boundary, aSIGBUSsignal would be delivered to the program and this would terminate the JVM. To prevent this situation, use the+u4option to the C and aCC compilers when compiling native that will directly access Java data members. This command-line option instructs the compiler to use a special sequence when dereferencing pointers to the 64-bit types. The special sequence correctly handles the cases in which a 64-bit type is misaligned.
When building native method implementations to be used with the kernel-threaded JVM, sources must be compiled with the following additional command-line options:
-D_HPUX -D_POSIX_C_SOURCE=199506L
Additionally developers who produce hybrid applications where the application entry point is a language other than Java, for example a C languagemain(), must link with thep-threadlibrary using-lpthreadon the link line in order to use the kernel-threaded JVM. Failing to link withlibpthread.sl(libpthread.soon Itanium) will result in an runtime failure when the JVM is loaded. Thelibpthreadlibrary was not available in releases prior to HP-UX 11.0.
Implementers of native methods called by Java main programs should take care to insure that null pointers are not dereferenced. The JVM is linked using the-zoption, which is discussed in the man page for the C compiler. If a native method does deference a null pointer aSIGSEGVwill be delivered to the JVM and this will cause the JVM to terminate.
HP provides the following two Java examples on how to call C and C++ from Java using the standard JNI calling mechanism. Code examples C++ for Java 1.3.1 and 1.4.2 follow.
Sample Java calling native method implementation in C
Here is the sample Java program that calls a native method, which has a C implementation:
//
// File TestJava2CallingNative.java
//
class TestJava2CallingNative {
native static void sayHelloWorld();
public static void main(String args[])
{
String libname = args[0];
try {
System.loadLibrary(libname);
System.out.println("Library " +
libname + " successfully loaded");
}
catch (UnsatisfiedLinkError Err) {
System.out.println("error: " + Err);
return;
}
System.out.println("Calling sayHelloWorld");
sayHelloWorld();
System.out.println("All done");
}
}
Compile this class:
$ <java_dir>/bin/javac -verbose TestJava2CallingNative.java
Output:
TestJava2CallingNative.class
Generate the JNI header file for this class. You must have the current directory in yourCLASSPATHfor the javah command to find your newly compiled class file.
$ <java_dir>/bin/javah -verbose -jni TestJava2CallingNative
Output:
TestJava2CallingNative.h
Here is the sample C native method implementation for sayHelloWorld:
/*
* File cImpl.c
*/
#include "TestJava2CallingNative.h"
#include <stdio.h>
JNIEXPORT void JNICALL
Java_TestJava2CallingNative_sayHelloWorld(JNIEnv *env, jclass class)
{
printf("C says HelloWorld via stdio\n");
}
To compile this C source file:
$ cc -Ae +u4 +z -c -D_HPUX -D_POSIX_C_SOURCE=199506L \
-I<java_dir>/include -I<java_dir>/include/hp-ux \
cImpl.c
Output:
cImpl.o
Note that you are required to supply either-Aaor-Aeas a command line option to the C compiler. The Java header files that you must include require support for ANSI C prototypes.
Create the shared library containing the native method implementation:
PA-RISC:
$ aCC -b -o libaCCImpl.sl aCCImpl.o \
-lstd -lstream -lCsup -lm
(see below for Itanium)
Output:
libcImpl.sl
(libcImpl.so on Itanium)
To execute the Java program, you must set theSHLIB_PATHenvironment variable to contain the location of the directory that containslibcImpl.sl(libcImpl.soonIPF).SHLIB_PATHis the HP-UX name forLD_LIBRARY_PATHand can contain a list of directories each separated by colons.
$ export SHLIB_PATH=.:$SHLIB_PATH
$ <java_dir>/bin/java TestJava2CallingNative cImpl
Library cImpl successfully loaded
Calling sayHelloWorld
C says HelloWorld via stdio
All done
Sample Java calling native method implementation in HP aC++
Here is a sample Java program that calls a native method which has a C++ implementation. This C++ example will use the aC++ compiler. HP has two different C++ compilers, and older cfront based product and a newer aC++ compiler. You can tell which C++ compiler you are using by the name of the driver. The older cfront based product uses CC as the driver, while the newer aC++ compiler uses aCC as the name of the driver. The official HP product names for these two C++ compilers are HP C++ for the cfront based product and HP aC++ for the new C++ compiler.
//
// TestJava2CallingNative.java
//
class TestJava2CallingNative {
public native static void sayHelloWorld();
public static void main(String args[]) {
try {
System.loadLibrary(libname);
System.out.println("Library " + libname + " successfully loaded");
} catch (UnsatisfiedLinkError err) {
System.out.println("error: " + err);
return;
}
System.out.println("initialize C++ runtime");
initialize();
System.out.println("Calling sayHelloWorld");
sayHelloWorld();
System.out.println("All done!");
}
The code above is very similar to the code in the C-based example; the only differences are the addition of the declaration and invocation of the native methodinitialize(). With the PA-RISC version of HP aC++ some internal C++ runtime data structures need to be initialized before transferring control to any C++ code. Theinitialize()method will perform the necessary initialization. With the Itanium version of HP aC++ this initialization step is no longer needed and theinitialize()method can be omitted.
Compile this class:
$ <java_dir>/bin/javac -verbose TestJava2CallingNative.java
Output:
TestJava2CallingNative.class
Generate the JNI header file for this class. You must have the current directory in yourCLASSPATHfor the javah command to find your newly compiled class file.
$ <java_dir>/bin/javah -verbose -jni TestJava2CallingNative
Output:
TestJava2CallingNative.h
Here is the sample C++ native method implementation for initialize and sayHelloWorld:
//
// File aCCImpl.C
//
#include "TestJava2CallingNative.h"
#include <iostream.h>
extern "C" {
void _main();
}
JNIEXPORT void JNICALL
Java_TestJava2CallingNative_initialize(JNIEnv *, jclass)
{
_main();
}
JNIEXPORT void JNICALL
Java_TestJava2CallingNative_sayHelloWorld(JNIEnv *, jclass)
{
cout << "aC++ says HelloWorld via iostreams"
<< endl;
}
In the above example you can see the additional native methodinitialize()simply calls the routine_main(). Since the Java Native interface does not allow us to call a routine name_maindirectly we have to write this wrapper function to allow us to call_mainindirectly. Also note that we need to useinitialization extern "C"to direct the C++ compiler not to perform name mangling on this routine. The entry point_mainis located in the PA-RISC version of the C++ runtime support librarylibCsup.sl.
Note:As mentioned above the additional initialization step is no longer necessary with the Itanium version of HP aC++. In fact calling _main from code compiled by the Itanium version of HP aC++ will result in_mainbeing an unresolved symbol.
Compile this C++ source file:
$ aCC +z +u4 -c -D_HPUX -D_POSIX_C_SOURCE=199506L
-I<java_dir>/include -I<java_dir>/include/hp-ux \
aCCImpl.C
Output:
aCCImpl.o
Create the shared library containing the native method implementation:
PA-RISC:
$ aCC -b -o libaCCImpl.sl aCCImpl.o \
-lstd -lstream -lCsup -lm
(see below for Itanium)
Output:
libaCCImpl.sl
(libaCCImpl.so on Itanium)
Note that the C++ driver program aCC must be used to create the shared library. Also note that an explicit dependency on three C++ runtime libraries need to be specified. The HP aC++ compiler has split the runtime support libraries into three separate shared libraries:libCsup.sl, libstream.slandlibstd.sl(libCsup.so, libstream.soandlibstd.soon Itanium).
All HP aC++ programs requirelibCsup.sl(libCsup.soon Itanium). The other two libraries are required by a subset of C++ programs. In this example, we could omitlibstd.slon PA since we are not using the Standard Template Library functionality. However it is usually best to link your native method shared library against all three of these libraries.
On Itanium, create the shared library using:
$ aCC -b -o libaCCImpl.so aCCImpl.o \
-lstd_v2 -lCsup -lunwind -lm
On Itanium,-lstd_v2is necessary, otherwise, running the program will result inUnsatisfiedLinkErrors.
Linking a shared library against these other shared libraries will cause the linker to record the fact that wheneverlibaCCImpl.sl(orlibaCCImpl.so) is loaded into memory the dependent librarieslibCsup.sl, libstream.slandlibstd.sl, (libCsup.so, libstream.soandlibstd.soon Itanium) also must be loaded. This is necessary sincelibCsup.sl(orlibCsup.so) contains the entry-point_mainas well as all the other necessary runtime support routines required by every C++ method.
To execute the Java program, you must set theSHLIB_PATHenvironment variable to contain the location of the directory that includeslibaCCImpl.sl(libaCCImpl.soon Itanium).SHLIB_PATHis the HP-UX name forLD_LIBRARY_PATHand can contain a list of directories each separated by colons.
$ export SHLIB_PATH=.:$SHLIB_PATH
$ <java_dir>/java TestJava2CallingNative aCCImpl
Library aCCImpl successfully loaded
initialize C++ runtime
Calling sayHelloWorld
ANSI C++ says HelloWorld via iostreams
All done
Native (non-Java) calling Java methods
The second capability that JNI provides is to allow non-Java to make calls into Java bytecode. This capability is provided via the C and C++ header file jni.h. Using this capability C and C++ programs can make calls into Java.
In Java 2, the Java Virtual Machine (JVM) is shipped as a shared library. To utilize the JVM in a native application you must link the application againstlibjvm.sl(libjvm.soon Itanium). The JNI supports an InvocationAPIthat allows you to create and initialize a new JVM. Using this newly created JVM you can invoke various Java methods, create new Java objects or access Java objects created by the JVM.
Here is the sample Java class that we will call from C and C++ programs:
//
// File TestNonJavaCallingJava2.java
//
public class TestNonJavaCallingJava2 {
public static void printInt(int arg)
{
System.out.println("TestNonJavaCallingJava2.\
printInt received: " + arg);
}
}
Compile the above Java file into byte code:
$ <java_dir>/bin/javac -verbose TestNonJavaCallingJava2.java
Output:
TestNonCallingJava2.class
HP provides the following two examples on how to call Java from C and C++ using the standard JNI calling mechanism.
Sample native calling Java implementation in C
Here is the sample C program. This program will use the JVM Invocation Interface to create a new JVM, find a class namedTestNonJavaCallingJava2, and find a Java method namedprintInt, and invoke the method with an argument of 100.
Note:
This program works as is for SDK 1.4.2. However, if you wish to take advantage of the new JNI features in 1.4.2, in the example below you should change the linevm_args.version = JNI_VERSION_1_2;tovm_args.version = JNI_VERSION_1_4;
/*
* File: c_main.c
*
* Example C Source File as the Main
* create a new Java Virtual Machine
* and locate the class TestNonJavaCallingJava2
* and invoke the static method printInt
*/
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
JNIEnv *env;
JavaVM *jvm;
JNIEnv jni;
JavaVM vmi;
JavaVMInitArgs vm_args;
JavaVMOption options[4];
jint res;
printf("beginning execution...\n");
/*
options[0].optionString = (char *) \
"-Djava.class.path=.";
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = JNI_FALSE;
/*
* The CLASSPATH environment variable does not
* set the classpath for JNI applications that
* have a native main program. This behavior
* is consistent with the JavaSoft reference platform.
*/
/*
* load and initialize a java vm,
* return a JNI interface ptr in env
*/
res = JNI_CreateJavaVM(&jvm,(void **)&env,&vm_args);
if (res != 0) {
printf("JNI_CreateJavaVM failed. %d\n", res);
exit(1);
}
jni = *env;
vmi = *jvm;
// Find the class
jclass cls = jni->FindClass(env, "TestNonJavaCallingJava2");
if (cls == 0) {
printf("Could not locate class NonJavaCallingJava2");
exit(1);
}
// Find the method
jmethodID mid = jni->GetStaticMethodID(env, cls, "printInt", "(I)V");
if (mid == 0) {
printf("Could not locate method printInt with signature (I)V");
exit(1);
}
// Invoke the method
jni->CallStaticVoidMethod(env, cls, mid, 100);
// we are done
vmi->DestroyJavaVM(jvm);
}
Compile the C source file:
$ cc -O -c -Ae +u4 -D_HPUX -D_POSIX_C_SOURCE=199506L \
-I<java_dir>/include -I<java_dir>/include/hp-ux c_main.c
Output:
c_main.o
Link the main executable.
cc -z -o c_main c_main.o \
-L<java_dir>/jre/lib/PA_RISC2.0/hotspot \
-ljvm -lpthread -llwp
On Itanium, the command to the main program would look like this:
$ cc -z -o cmain cmain.o \
-L<java_dir>/jre/lib/IA64/hotspot \
-ljvm -lpthread
Output:
c_main
Notes:
- If you are using SDK 1.2 or 1.3 and your C main is linkedEXEC_MAGICso as to be able to address more than 1GBof private data, you must use the Hotspot JVM, or use the Classic JVM with the
"-nojit" option. TheJITcompiler in Classic 1.2 and 1.3 is not compatible withEXEC_MAGIC.
To execute the C main program, set theSHLIB_PATHenvironment variable so the jvm libraries can be loaded.
$ export SHLIB_PATH=<java_dir>/jre/lib/PA_RISC2.0:\
<java_dir>/lib/PA_RISC2.0/hotspot
$ export CLASSPATH=.
./c_main
TestNonJavaCallingJava.printInt received: 100
To access Itanium libraries, change PA_RISC2.0 to IA64.
Sample native calling Java implementation in HP aC++
Here is the sample HP aC++ program. This program will use the C++ object-oriented interface provided in the JVM Invocation Interface to create a new JVM, find a class namedTestNonJavaCallingJava2, and find a Java method namedprintInt, and invoke the method with an argument of 100.
Note:
This program works as is for SDK 1.4.2. However, if you wish to take advantage of the new JNI features in 1.4.2, in the example below you should change the linevm_args.version = JNI_VERSION_1_2;tovm_args.version = JNI_VERSION_1_4;
//
//Example : aC++ Source File as the Main
//create a new Java Virtual Machine
//and locate the class TestNonJavaCallingJava2
//and invoke the static method printInt
#include <jni.h>
#include <iostream.h>
#include <stdlib.h>
int main()
{
JNIEnv *env;
JavaVM *jvm;
JNIEnv jni;
JavaVM vmi;
JavaVMInitArgs vm_args;
JavaVMOption options[4];
jint res;
cout << "beginning execution..." << endl;
options[0].optionString = (char *) \
"-Djava.class.path=."; /* user classes */
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = JNI_FALSE;
// load and initialize a java vm, return a JNI interface ptr in envcout << "before CreateJavaVM" << endl; res = JNI_CreateJavaVM(&jvm,(void **)&env,&vm_args);if (res != 0) { cerr << "JNI_CreateJavaVM failed %d\n" << res << "." << endl; exit(1); } else cout << "after CreateJavaVM " << endl;// Find the classcout << "before FindClass" << endl;jclass cls=env->FindClass("TestNonJavaCallingJava2");if (cls == 0) { cerr << "Could not locate class NonJavaCallingJava2 in the class path" \ << options[0].optionString << "." << endl; exit(1); }else cout << "after FindClass" << endl;// Find the methodjmethodID mid=env->GetStaticMethodID(cls, "printInt", "(I)V");if (mid == 0) { cerr << "Could not locate method printInt with signature (I)V" " in the class TestNonJavaCallingJava." << endl; exit(1); } // Invoke the methodenv->CallStaticVoidMethod(cls, mid, 100);// we are donejvm->DestroyJavaVM();}
Compile the aC++ source file:
$ aCC -c -ext -D_HPUX -D_POSIX_C_SOURCE=199506L \
-I<java_dir>/include -I<java_dir>/include/hp-ux \
aCC_main.C
Output:
aCC_main.o
Create the main program and link:
$ aCC -z -o aCC_main aCC_main.o \
-L<java_dir>/jre/lib/PA_RISC2.0/hotspot \
-ljvm -lpthread -llwp
Notes:
- If you are using SDK 1.2 or 1.3 and your C main is linkedEXEC_MAGICso as to be able to address more than 1GB of private data, you must either use Hotspot JVM or the Classic JVM with the "-nojit" option. The JIT compiler in Classic 1.2 and 1.3 is not compatible withEXEC_MAGIC.
Output:
aCC_main
To execute the aCC main program, you need to set the following environment variables so the JVM libraries can be loaded.
$ export SHLIB_PATH=<java_dir>/jre/lib/PA_RISC2.0:\
<java_dir>/lib/PA_RISC2.0/hotspot
$ export CLASSPATH=.
To access Itanium libraries change PA_RISC2.0 to IA64.
Now the program can be run:
./aCC_main
TestNonJavaCallingJava.printInt received: 100
Main/Primordial thread stack size limits
The primordial thread is the first thread when a process is created. This is the thread that has the main method. It is also called the main thread. The primordial thread stack size is controlled by the kernel parametermaxssizormaxssiz_64bit. The Java VM (JVM) has two options for controlling the stack size:
-XX:MainThreadStackSize=n
-Xss[n][k or m]
In the Java VM the size of the primordial thread is restricted to the *greater* ofMainThreadStackSize(default 2M) orThreadStackSize(specified by-Xss). For example, if you specify-Xss1m, the JVM still takes 2M for the main thread. And if you specify-Xss4m, the JVM takes 4M for the main thread as well.
If your application callsJNI_CreateJavaVMorJNI_AttachCurrentThreadfrom the primordial thread, under certain conditions the stack usage could cross the JVM-imposed primordial thread stack size limit of 2M and cause a stack overflow situation in the native code itself, even if no Java code was ever run on the primordial thread.
Another point to consider is the effect ofmaxssizon the overall amount of writeable data space available to the application. The kernel automatically protects some memory abovemaxssizaway from the primordial stack base to enforce themaxssizlimit. If themaxssizis very large, this space between the base and the protected stack top is permanently reserved for potential stack space, and it is not available for any other writeable data use such as C heap, Java heap, or other thread stacks. Therefore if you need to have the maximum amount of writeable data space available to your application, you may want to consider reducing themaxssiz. Remember, though, thatmaxssizaffects all applications running on the system.
Example
Consider the following example. An application callsJNI_CreateJavaVMfrom the primordial thread, which installs a stack overflow check at more or less 2MB above theJNI_CreateJavaVMframe. The application then makes function calls via recursion or otherwise that result in a very deep stack on the same thread independent of calling back into Java. The stack usage could cross the JVM-imposed primordial thread stack size limit of 2M and cause a stack overflow situation in the native code itself. In this case the JVM cannot take any action to resolve the problem, and the process aborts with the message:
"An irrecoverable stack overflow has occurred."
You need to distinguish stack overflow failures in the primordial thread from those occurring in other threads. If the overflow is in a Java thread, the error log generated will report the current Java thread, which can be used to identify the thread that caused the stack overflow failure. In the JVM diagnostic output, you would see a message like this:
An irrecoverable stack overflow has occurred.
An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : 10 occurred at PC=0x2D10
Function=__d_trap
Library=./crjvmzon
Current Java thread:
"main" prio=7 tid=4000a1b8 nid=1 lwp_id=127233 runnable [0x00000000..0x6fff0b08]
Dynamic libraries:
./crjvmzon
/opt/java1.4/jre/lib/PA_RISC2.0/server/libjvm.sl
[...]
Above, you can see that the error happened on the "main" thread, that is, the one that calledJNI_CreateJavaVM.
Workarounds
Here are three suggestions to work around a stack overflow problem in the main thread, listed from most desirable to least.
- Use the option-XX:MainThreadStackSize=<value>to increase the primordial thread stack size, However be aware that -XXoptions are non-standard options, and are liable to change from release to release.
- Use the-Xssoption to set the thread stack size. This workaround may be less desirable because-Xsssets the stack size for all threads, not just the primordial thread. For example, if your application has 100 threads and you set the maximum thread stack size to 4M with the-Xssoption, the application would use nearly 400MB of address space just for thread stacks. If you did not use the-Xssoption, the application would have only used 50MB (512k (the default-Xssvalue) * 100 threads) of address and swap space.
- Change the application so as to CallJNI_CreateJavaVM()from a non primordial thread. That is, create a new thread with an appropriate stack size, usingpthread_create()and use this new thread to initialise the JVM.
Non-Main/Primordial thread stack size limits
The default stack size for 1.4 64-bit mode threads created by the JVM is 1MB. On PA-RISC 32 and 64-bit systems, the default stack size for threads created using thepthreadlibrary is 64KB.
Here are some suggestions to work around stack overflow problems in threads other than the main thread:
- If the thread is created in native code and is attached to Java throughJNI_AttachCurrentThread, increase the stack size attribute when creating the thread withpthread_create.
- If the thread is created inside Java and there is a stack overflow condition, increase the thread stack size with-Xss<n>
Dynamically loading the Hotspot JVM (SDK 1.3.1.x and 1.4.2.x PA-RISC)
Normally you would link against the JRE and use HotSpot, but sometimes you might want to load the JVM dynamically, especially if you are integrating Java with legacy applications.
(The example for Dynamically loading the Classic JRE can now be found in theAppendix.)
Note:The examples below work as is for Java 1.3.1.x and 1.4.2.x on PA-RISC. If you wish to take advantage of the new JNI features in 1.4.2, in the example below you should change the linevm_args.version = JNI_VERSION_1_2;tovm_args.version = JNI_VERSION_1_4;
Below is an example of how to dynamically load the shared librarylibjvm.sl, (libjvm.sofor Itanium), create a new JVM, locate the classTestNonJavaCallingJava2, and invoke the static methodprintInt.
#include <jni.h>#include <stdlib.h>#include <dl.h>typedef int (*JNI_CreateJavaVM_t)(JavaVM**, void**, void*);int main(){ JNIEnv *env; JavaVM *jvm; JNIEnv jni; JavaVM vmi; JavaVMInitArgs vm_args; JavaVMOption options[4]; jint res; printf ("beginning execution...\n"); options[0].optionString = (char *) "-Djava.class.path=."; /* user classes */ vm_args.version = JNI_VERSION_1_2; vm_args.options = options; vm_args.nOptions = 1; vm_args.ignoreUnrecognized = JNI_FALSE; // load libjvm.sl (PA-RISC) or libjvm.so (Itanium) shl_t libsym = shl_load("libjvm.sl", BIND_IMMEDIATE|DYNAMIC_PATH, 0L); if (libsym == 0) { fprintf(stderr, "Unable to shl_load libjvm.sl\n"); exit (1); } else fprintf(stdout, "shl_loaded libjvm.sl successfully!\n"); // find function JNI_CreateJavaVM JNI_CreateJavaVM_t func = NULL; res = shl_findsym(&libsym, "JNI_CreateJavaVM", TYPE_PROCEDURE, &func); if (res == 0) fprintf(stdout, "Found symbol JNI_CreateJavaVM!\n"); else { fprintf(stderr, "Unable to find symbol JNI_CreateJavaVM!\n"); exit (1); } // load and init a java vm, return a JNI interface ptr in env printf ("before CreateJavaVM\n"); res = (*func)(&jvm, (void **)&env, (void *)&vm_args); if (res != 0) { fprintf (stderr, "JNI_CreateJavaVM failed. %d\n", res); exit (1); } else fprintf (stdout, "after CreateJavaVM \n"); jni = *env; vmi = *jvm; // find the class fprintf (stdout, "before FindClass\n"); jclass cls=env->FindClass("TestNonJavaCallingJava2"); if (cls == 0) { fprintf (stderr, "Could not locate class TestNonJavaCallingJava2 in classpath %s\n", options[0].optionString); exit(1); } else fprintf (stdout, "after FindClass\n");// find the methodjmethodID mid=env->GetStaticMethodID(cls, "printInt", "(I)V");if (mid == 0) {fprintf (stderr, "Could not locate method printInt with signature (I)V in theclass TestNonJavaCallingJava.");exit(1);}else fprintf (stdout, "after GetStaticMethod\n");fflush (stdout); // invoke the methodenv->CallStaticVoidMethod(cls, mid, 100);// we are donejvm->DestroyJavaVM();} To compile the program:aCC --c loadjava.cpp -mt -ext -D_HPUX -D_POSIX_C_SOURCE=199506L \ -I<java_dir>/include -I<java_dir>/include/hp-ux Linking the program:To link the program onPA-RISC:aCC -z -mt -o loadjava loadjava.o -lpthreadTo link the program onItanium:aCC -z -mt -o loadjava loadjava.o -lpthread# allow use of SHLIB_PATH to locate shared libraries required by program
chatr +s enable loadjavaTo execute the program, set environment variables. The example is forPA-RISC. ForItaniumSDK 1.3.1.x, substitute IA64 for PA_RISC2.0 in the command below. ForItaniumSDK 1.4.2.x substitute IA64N for PA_RISC2.0 in the command below.export SHLIB_PATH=$JAVA_HOME/jre/lib/PA_RISC2.0/hotspot:$JAVA_HOME/jre/lib/PA_RISC2.0export CLASSPATH=. (Note: we are using the same TestNonJavaCallingJava2.class from prior examples)# Run program# Use JAVA_PRELOAD_ONCE if want to dynamically load library with TLS (e.g. HotSpot). For Itanium,substitute IA64 or IA64N for PA_RIS2.0, and substitute libjvm.so for libjvm.slJAVA_PRELOAD_ONCE=$JAVA_HOME/jre/lib/PA_RISC2.0/hotspot/libjvm.sl ./loadjava# Output:#TestNonJavaCallingJava.printInt received: 100
» | Java Native Interface: Programmer's Guide and Specification by Sheng Liang |
» | Please let us know additional information you'd like to see in the programmer's guide. |
Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems,Inc. in theU.S.and other countries. Hewlett-Packard is independent of Sun Microsystems, Inc
'Java' 카테고리의 다른 글
Java™ Troubleshooting Guide for HP-UX Systems (0) | 2007.04.03 |
---|---|
Java SE Application Design With MVC (0) | 2007.03.24 |
Using VC++ components from Java program (0) | 2007.03.23 |