0

I have wrapped a Java library into a C++ class library and wish to use this library within another C++ project.

Specifically, I would like to use the library within a class method which reads in an input file, loops over all elements in the file, and then utilizes the library to perform some operation.

However, I am trying to figure out exactly how to invoke the JVM correctly. At the minute my code looks something like this:

void myclass::method()
{
    for (int OBJECT=1; OBJECT < OBJECT_DATA_SIZE; OBJECT++)
    {

    // CONFIGURE JVM

       JavaVMOption jvmopt[1];
       jvmopt[0].optionString = "-Djava.class.path="
               "/PATH/TO/LIB/ONE.jar:"
               "/PATH/TO/LIB/TWO.jar:"
               "/PATH/TO/LIB/THREE.jar";

       JavaVMInitArgs vmArgs;
       vmArgs.version = JNI_VERSION_10;
       vmArgs.nOptions = 1;
       vmArgs.options = jvmopt;
       vmArgs.ignoreUnrecognized = JNI_FALSE;


    // CREATE THE JVM

       JavaVM *javaVM;
       JNIEnv *env;
       long flag = JNI_CreateJavaVM(&javaVM, (void**)&env, &vmArgs);

       if (flag == JNI_ERR)
       {                                                       // Check for errors and if errors exist
          std::cout << "\nError creating VM. Exiting...\n" << std::endl;           // Output message to console and exit
          env->ExceptionCheck();
          env->ExceptionDescribe();
          std::abort();
       }

       javaVM->DestroyJavaVM();     // If not found, destroy VM
    }
}

Every loop it is destroying and re-creating the JVM. First iteration it runs fine, but the second loop fails and crashes. I'm guessing this is something to do with the JVM not being correctly shut down. Log contents:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fa7a7d970c3, pid=32015, tid=32015
#
# JRE version: Java(TM) SE Runtime Environment (10.0.2+13) (build 10.0.2+13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (10.0.2+13, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# V  [libjvm.so+0x9180c3]  ThreadStateTransition::transition_from_native(JavaThread*, JavaThreadState) [clone .constprop.232]+0x13
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %d %P" (or dumping to /home/code/myProg/core.32015)
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#

---------------  S U M M A R Y ------------

Command Line: 

Host: Intel(R) Xeon(R) Gold 6130 CPU @ 2.10GHz, 32 cores, 62G, Ubuntu 18.04.1 LTS
Time: Tue Nov 13 14:44:44 2018 GMT elapsed time: 0 seconds (0d 0h 0m 0s)

---------------  T H R E A D  ---------------

Current thread is native thread

Stack: [0x00007ffcb58f3000,0x00007ffcb59f3000],  sp=0x00007ffcb59f0490,  free space=1013k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x9180c3]  ThreadStateTransition::transition_from_native(JavaThread*, JavaThreadState) [clone .constprop.232]+0x13
V  [libjvm.so+0x91b0a4]  jni_ExceptionCheck+0x34


siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0x00000000000002e8

Register to memory mapping:

RAX=
[error occurred during error reporting (printing register info), id 0xb]

Registers:
RAX=0x00007fa7a884facb, RBX=0x0000000000000000, RCX=0x0000000000000b40, RDX=0x0000000000000000
RSP=0x00007ffcb59f0490, RBP=0x00007ffcb59f04a0, RSI=0x00007fa7a610b8c0, RDI=0x0000000000000000
R8 =0x00007fa7a610b8c0, R9 =0x00007fa7a8aed7c0, R10=0x000000000000000a, R11=0x0000000000000000
R12=0x0000556a366a6a70, R13=0x0000000000000001, R14=0x00007ffcb59f09a0, R15=0x0000000000000001
RIP=0x00007fa7a7d970c3, EFLAGS=0x0000000000010206, CSGSFS=0x002b000000000033, ERR=0x0000000000000006
  TRAPNO=0x000000000000000e

Top of Stack: (sp=0x00007ffcb59f0490)
0x00007ffcb59f0490:   0000556a35a370a0 0000556a366a6800
0x00007ffcb59f04a0:   00007ffcb59f04d0 00007fa7a7d9a0a4
0x00007ffcb59f04b0:   0000000000000001 0000556a35a370a0
0x00007ffcb59f04c0:   00007fa7a6e9a0a0 00007fa7a6e9a0a0 

Instructions: (pc=0x00007fa7a7d970c3)
0x00007fa7a7d970a3:   c6 83 29 04 00 00 00 eb 9f 0f 1f 40 00 55 48 89
0x00007fa7a7d970b3:   e5 53 48 89 fb 48 83 ec 08 48 8d 05 08 8a ab 00
0x00007fa7a7d970c3:   c7 87 e8 02 00 00 05 00 00 00 80 38 00 75 0c 48
0x00007fa7a7d970d3:   8d 05 73 a8 b1 00 83 38 01 74 30 48 8d 05 e5 89 


---------------  P R O C E S S  ---------------

VM state:at safepoint (shutting down)

VM Mutex/Monitor currently owned by a thread:  ([mutex/lock_event])
[0x0000556a366a30d0] Threads_lock - owner thread: 0x0000556a36917800

Heap address: 0x00000003d6c00000, size: 16020 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
Narrow klass base: 0x0000000000000000, Narrow klass shift: 3
Compressed class space size: 1073741824 Address: 0x00000007c0000000

Heap:
 garbage-first heap   total 1028096K, used 0K [0x00000003d6c00000, 0x00000007c0000000)
  region size 4096K, 1 young (4096K), 0 survivors (0K)
 Metaspace       used 3331K, capacity 4480K, committed 4480K, reserved 1056768K
  class space    used 280K, capacity 384K, committed 384K, reserved 1048576K
Heap Regions: E=young(eden), S=young(survivor), O=old, HS=humongous(starts), HC=humongous(continues), CS=collection set, F=free, A=archive, TS=gc time stamp, AC=allocation context, TAMS=top-at-mark-start (previous, next)

What should I be doing differently?

Ddor
  • 347
  • 1
  • 12
  • I'm not sure I understand why you can't reuse the JVM between iterations(?). In any case, a process can as far as I know only create a JVM _once_. – Michael Nov 13 '18 at 16:40
  • Hi Michael, thanks for your input. I initially thought that by creating and then destroying a JVM it might be safer in the sense that if there are any memory leaks, destroying the JVM would allow all JNI references within the JVM to be released. Since I now believe there are issues "destroying" a JVM within a process , I guess my only option is to create a single JVM instance once. Thanks – Ddor Nov 13 '18 at 16:49
  • Michael is correct - you can only call JNI_CreateJavaVM exactly once. For references see: https://stackoverflow.com/questions/50630057/can-you-create-multiple-jvms-in-jni-in-a-single-process/50630418#50630418 – valiano Nov 14 '18 at 19:14

0 Answers0