X

Poonam Bajaj's Blog

  • February 16, 2016

Using NMT with custom JVM launcher

Poonam Parhar
Consulting Member of Technical Staff
I recently worked with a customer, facing problem in using Native Memory Tracker with their custom JVM launcher created using the JNI API JNI_CreateJavaVM, and learned how NMT can be enabled when used with the custom JVM launchers (non 'java' launchers). This blog post shares details on how that can be done.

Let's start with the following JNI code example where I am passing the JVM option -XX:+NativeMemoryTracking=detail as an argument while creating the JVM with JNI_CreateJavaVM call. -XX:+NativeMemoryTracking=detail option should enable the Native Memory Tracker at the detail level.
JavaVM *javaVM;
JNIEnv *env;       
// VM initialization arguments 
JavaVMInitArgs vmArgs;
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-XX:+NativeMemoryTracking=detail";
vmArgs.version = JNI_VERSION_1_8;
vmArgs.nOptions = 1;
vmArgs.options = options;
vmArgs.ignoreUnrecognized = false;
// Create Java VM
JNI_CreateJavaVM(&javaVM, (void**)&env, &vmArgs);
delete options;    

Compile code with the following:

JAVA_INCLUDES=-I$(JAVA_HOME)/include/ -I$(JAVA_HOME)/include/$(JAVA_OS)/ -L$(JAVA_HOME)/jre/lib/amd64/server
g++ jnicode.cpp $(JAVA_INCLUDES) -ljvm

When this program is compiled using the above compile command, and executed, it reports the following error:

Java HotSpot(TM) 64-Bit Server VM warning: Native Memory Tracking did not setup properly, using wrong launcher?

The reason for this behavior is that the Native Memory Tracker requires an environment variable to be set for the process before the JVM can be initialized and created. That environment variable is NMT_LEVEL_<pid> where <pid> is the identifier of the process. Also, please note that since this environment variable should already be set before the JVM gets initialized, we need to dynamically load the JVM shared library at runtime after setting the env variable .

Here's the sample code showing how we can do that:

// env variable to be set for NMT
const char*  NMT_Env_Name    = "NMT_LEVEL_";
const int TOTAL_LEN = strlen(NMT_Env_Name)+20;
char *nmtEnv = (char*)calloc(TOTAL_LEN,1);
snprintf(nmtEnv,TOTAL_LEN, "%s%d", NMT_Env_Name, getpid());
// Set the env variable
setenv(nmtEnv, "detail", 1);

// Dynamically load libjvm.so
const char* jvmpath = "<path to libjvm.so>/libjvm.so";
void* libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
if (libjvm == NULL) {
printf("Could not open libjvm.so\n");
return -1;
}
// VM initialization arguments 
JavaVMInitArgs vmArgs; 
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-XX:+NativeMemoryTracking=detail";
vmArgs.version = JNI_VERSION_1_8;
vmArgs.nOptions = 1;
vmArgs.options = options;
vmArgs.ignoreUnrecognized = false;
// get a handle to JNI_CreateJavaVM function in the dynamically loaded JVM
CreateJavaVM_t CreateJavaVM;
CreateJavaVM = (CreateJavaVM_t)dlsym(libjvm, "JNI_CreateJavaVM");
// Create the JVM
JavaVM *javaVM;
JNIEnv *jniEnv;
long flag = CreateJavaVM(&javaVM, (void**)&jniEnv, &vmArgs);

Compile code with the following:

g++ jnivm.cc $(JAVA_INCLUDES) -ldl

In the above example code, I am setting env variable NMT_LEVEL_<pid> and dynamically loading libjvm.so after setting this env variable. Note that I removed -ljvm from the g++ options so as not to load the JVM shared library at the process load time. With these simple changes, NMT can be used with the custom JVM launchers.

Join the discussion

Comments ( 2 )
  • Allen Reese Tuesday, October 11, 2016

    Thanks Poonam, I had teased this out from talking with Support.

    There is one more tricky thing this code doesn't cover, and that's -Xss.

    To set the stack size correctly you need to create a new thread using pthreads and set it's stack size before you start it, and then create the JVM from the new thread. :)

    I've got buildable code for both here:

    https://github.com/areese/launch_jvm_from_jni


  • Poonam Tuesday, October 11, 2016

    Thanks Allen!


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.