I am trying to create a Java to .Net interop and the way I am doing it is by creating a C# com object and a native unmanaged c++ dll that uses JNIEnv of java.
the java is loading the native c++ dll and invokes a method in it which invokes a method on
The command passed from java to .Net is a byte array and the response passed back is also a byte array
the C# managed COM object which finally invokes a method on a regular C# managed dll.
My C# com object code is as follows:
(I am not showing all code, only relevent sections)
************************************************** ************
public class CommandExecutor : ICommandExecutor
{
public byte[] ExecuteCommand(byte[] command)
{
return MyStaticClass.ExecuteCommand(command);
}
}
************************************************** ************
MyStaticClass is a static class that executes the given command in a managed referenced C#
dll.
My C++ code is:
************************************************** ************
JNIEXPORT jbyteArray JNICALL
Java_com_gigaspaces_serialization_pbs_commands_Dis patcher_executeCommand
(JNIEnv *env, jobject obj, jbyteArray jstr)
{
jboolean iscopy;
jbyteArray answerArray = 0;
SAFEARRAY *psaOut = 0;
SAFEARRAY *psa;
jbyte* pBuff;
int len = env->GetArrayLength(jstr);
pBuff = env->GetByteArrayElements(jstr,&iscopy);
pBuff[len]=0;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = len;
psa = SafeArrayCreate(VT_UI1,1,rgsabound);
for (long i=0; i < len; i++)
SafeArrayPutElement(psa,&i,(void *)&pBuff[i]);
pServicePtr->ExecuteCommand( psa, &psaOut);
if(psaOut != 0)
{
len = psaOut->rgsabound[0].cElements;
answerArray = env->NewByteArray(len);
env->SetByteArrayRegion(answerArray, 0, len, (jbyte*)psaOut->pvData);
}
env->ReleaseByteArrayElements(jstr, pBuff, 0);
SafeArrayDestroy(psa);
return answerArray;
}
************************************************** ************
pServicePtr points to an instance of the C# com object.
The java loads the dll containing this c++ code and use the native mechanizm to invoke the
method through JNI.
the java code is like this:
************************************************** ************
public static ByteArrayInputStream execute(ByteArrayOutputStream output)
{
byte[] inputBuffer = executeCommand(output.toByteArray());
// If null is returned a serious error happened on delegator side
if (inputBuffer == null)
throw new RuntimeException(
"Unexpected error happend on delegator side, see delegators
log for more information");
ByteArrayInputStream input = new ByteArrayInputStream(inputBuffer);
return input;
}
private static native byte[] executeCommand(byte[] command);
************************************************** ************
This solution seems to work fine however in an unconsistent way the JVM crashes sometimes with
the following error (Not showing the entire dump)
************************************************** ************
#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x7c93426d, pid=1340, tid=7144
#
# Java VM: Java HotSpot(TM) Server VM (1.5.0_12-b04 mixed mode)
# Problematic frame:
# C [ntdll.dll+0x3426d]
#
--------------- T H R E A D ---------------
Current thread (0x00880740): JavaThread "LRMI Connection--pool-1-thread-13" daemon
[_thread_in_vm, id=7144]
siginfo: ExceptionCode=0xc0000005, reading address 0x00000000
Registers:
EAX=0x00000000, EBX=0x00000100, ECX=0x045452c8, EDX=0x00000000
ESP=0x0657f4a4, EBP=0x0657f6c4, ESI=0x04541c38, EDI=0x04544ac0
EIP=0x7c93426d, EFLAGS=0x00010246
Top of Stack: (sp=0x0657f4a4)
0x0657f4a4: 00002e7f 00002e80 00880740 00000000
0x0657f4b4: 0657f938 00b12d15 00000000 0657f93c
0x0657f4c4: 00000001 0657f940 0657f944 0657f508
0x0657f4d4: 0657f948 0657f94c 0657f90c 00881c54
0x0657f4e4: 00881c50 0657f910 0657f914 0657f6b4
0x0657f4f4: 00881c40 00881c44 00000b00 00880740
0x0657f504: 101daf00 03fb5008 6db4169d 0657f6b4
0x0657f514: 00cdc9f0 6daf3dce 00cdad48 0657f950
Instructions: (pc=0x7c93426d)
0x7c93425d: 11 89 95 64 ff ff ff 8b 40 0c 89 85 5c ff ff ff
0x7c93426d: 8b 00 3b 42 04 0f 85 13 01 00 00 3b c1 0f 85 0b
Stack: [0x06540000,0x06580000), sp=0x0657f4a4, free space=253k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [ntdll.dll+0x3426d]
C [msvcrt.dll+0x1c3c9]
C [msvcrt.dll+0x1c3e7]
C [msvcrt.dll+0x1c42e]
V [jvm.dll+0x21de76]
C [JNetBridgeCpp.dll+0x12f0]
C [JNetBridgeCpp.dll+0x1133]
j com.gigaspaces.serialization.pbs.commands.Dispatch er.executeCommand([B)[B+0
j com.gigaspaces.serialization.pbs.commands.Dispatch er.a(Ljava/io/ByteArrayOutputStream;)
Ljava/io/ByteArrayInputStream;+4
j com.j_spaces.obf.mb.a(ILjava/util/List;)V+13
************************************************** ************
It seems as if I have some kind of a memory override (maybe a leak but it doesn't seem like an
out of memory exception) maybe in the C++ dll.
Can anyone help? I am stuck!!!
Thoughts I have are:
-Who is incharge of freeing the memory of the byte[] returned by the C# com object, the COM object or the C++ dll? Anyhow I tried to call SafeArrayDestroy(psaOut); and it didn't help
-What happens if the C# garbage collector decide to move the byte[] returned by execute command location in the memory while the C++ dll is still using it? Can I pin memory allocation on return values?
JNetBridgeCpp.dll is my CPP dll