JNI troubles (newbie)

V

Vig

Hi,

I need to get a C program to talk to Java and I am using JNI. I have created
a dll that the Java code loads. The C code reads from a file and stores some
data in the heap. I can get the dll to send data back and forth to the Java
code, but its not possible to free the variables pointing to the heap since
that data is reused several times. I have so far been getting rtlallocate
and rtlfreeheap errors. Is this something that can be done safely? Or is
there somehting inherently wrong with this method?
 
V

Vig

Vig said:
Hi,

I need to get a C program to talk to Java and I am using JNI. I have created
a dll that the Java code loads. The C code reads from a file and stores some
data in the heap. I can get the dll to send data back and forth to the Java
code, but its not possible to free the variables pointing to the heap since
that data is reused several times. I have so far been getting rtlallocate
and rtlfreeheap errors. Is this something that can be done safely? Or is
there somehting inherently wrong with this method?

This is the error I get:

An unexpected exception has been detected in native code outside the VM.

Unexpected Signal : EXCEPTION_ACCESS_VIOLATION (0xc0000005) occurred at
PC=0x77FCC8E1

Function=RtlFreeHeap+0x29D

Library=C:\WINNT\system32\ntdll.dll

Current Java thread:

at com.engineous.gui.NativeLoader.init(Native Method)

at
com.engineous.gui.VisualDesignDriverWindow.vddInit(VisualDesignDriverWindow.
java:99)

at
com.engineous.gui.VisualDesignDriverWindow.main(VisualDesignDriverWindow.jav
a:511)

Dynamic libraries:

0x00400000 - 0x0040B000 C:\Program Files\Java\j2re1.4.2_06\bin\javaw.exe

0x77F80000 - 0x77FFD000 C:\WINNT\system32\ntdll.dll

0x7C2D0000 - 0x7C332000 C:\WINNT\system32\ADVAPI32.dll

0x7C570000 - 0x7C623000 C:\WINNT\system32\KERNEL32.DLL

0x77D30000 - 0x77DA1000 C:\WINNT\system32\RPCRT4.DLL

0x77E10000 - 0x77E75000 C:\WINNT\system32\USER32.dll

0x77F40000 - 0x77F7B000 C:\WINNT\system32\GDI32.DLL

0x78000000 - 0x78045000 C:\WINNT\system32\MSVCRT.dll

0x75E60000 - 0x75E7A000 C:\WINNT\system32\IMM32.DLL

0x08000000 - 0x08139000 C:\Program
Files\Java\j2re1.4.2_06\bin\client\jvm.dll

0x77570000 - 0x775A0000 C:\WINNT\system32\WINMM.dll

0x681A0000 - 0x681A7000 C:\WINNT\system32\serwvdrv.dll

0x66740000 - 0x66747000 C:\WINNT\system32\umdmxfrm.dll

0x10000000 - 0x10007000 C:\Program Files\Java\j2re1.4.2_06\bin\hpi.dll

0x007E0000 - 0x007EE000 C:\Program Files\Java\j2re1.4.2_06\bin\verify.dll

0x007F0000 - 0x00809000 C:\Program Files\Java\j2re1.4.2_06\bin\java.dll

0x00810000 - 0x0081D000 C:\Program Files\Java\j2re1.4.2_06\bin\zip.dll

0x18470000 - 0x18582000 C:\Program Files\Java\j2re1.4.2_06\bin\awt.dll

0x77800000 - 0x7781E000 C:\WINNT\system32\WINSPOOL.DRV

0x76620000 - 0x76630000 C:\WINNT\system32\MPR.DLL

0x77A50000 - 0x77B3F000 C:\WINNT\system32\ole32.dll

0x18590000 - 0x185E1000 C:\Program
Files\Java\j2re1.4.2_06\bin\fontmanager.dll

0x72800000 - 0x72846000 C:\WINNT\system32\ddraw.dll

0x728A0000 - 0x728A6000 C:\WINNT\system32\DCIMAN32.dll

0x72CF0000 - 0x72D84000 C:\WINNT\system32\D3DIM700.DLL

0x6B7E0000 - 0x6B7EF000 C:\Spring2005Coop\Visual Design Driver
New\dll\NativeLoader.dll

0x1DEE0000 - 0x1DF5E000 C:\WINNT\system32\DFORMD.dll

0x77920000 - 0x77943000 C:\WINNT\system32\imagehlp.dll

0x72A00000 - 0x72A2D000 C:\WINNT\system32\DBGHELP.dll

0x690A0000 - 0x690AB000 C:\WINNT\system32\PSAPI.DLL

Heap at VM Abort:

Heap

def new generation total 576K, used 164K [0x10010000, 0x100b0000,
0x104f0000)

eden space 512K, 19% used [0x10010000, 0x100291a0, 0x10090000)

from space 64K, 99% used [0x100a0000, 0x100afff8, 0x100b0000)

to space 64K, 0% used [0x10090000, 0x10090000, 0x100a0000)

tenured generation total 1408K, used 297K [0x104f0000, 0x10650000,
0x14010000)

the space 1408K, 21% used [0x104f0000, 0x1053a728, 0x1053a800, 0x10650000)

compacting perm gen total 4096K, used 3584K [0x14010000, 0x14410000,
0x18010000)

the space 4096K, 87% used [0x14010000, 0x14390298, 0x14390400, 0x14410000)

Local Time = Fri Feb 11 13:31:47 2005

Elapsed Time = 8

#

# The exception above was detected in native code outside the VM

#

# Java VM: Java HotSpot(TM) Client VM (1.4.2_06-b03 mixed mode)

#



Any ideas?
 
C

Chris Uppal

Vig said:
I need to get a C program to talk to Java and I am using JNI. I have
created a dll that the Java code loads. The C code reads from a file and
stores some data in the heap. I can get the dll to send data back and
forth to the Java code, but its not possible to free the variables
pointing to the heap since that data is reused several times.

I'm not sure what you mean.

Do you mean that you want to allocate stuff in the 'C' heap, have Java objects
"know" about that data, and have it somehow magically cleaned up for you
(perhaps by the Java GC) ? If so then that won't work.

I'm guessing at what you are trying to do here, so the following may be
inappropriate, irrelevant, Just Plain Wrong ;-) But..

First decide /where/ the data is gong to be stored.

If you keep it as Java byte[] arrays (or similar) then the Java GC can and will
look after it for you, but you'll probably have more complicated code to create
and fill in those arrays from the 'C' side.

If you keep it in the 'C' malloc arena (or similar) then you'll have to manage
allocation and deallocation yourself. If Java objects have some kind of access
to that data, then they will also have to take part in that management, and
that will not happen automatically. One way to handle it would be to keep a
reference count for each malloc()-ed 'C' block and free() it only when that
count drops to zero. You Java objects will have to be careful (just as C code
would be) to keep the reference counts correct. You'll probably have to use
finalisation (or similar) to ensure that the 'C' reference counts are
decremented when Java objects are GCed.

Fairly complicated, and unfortunately rather error-pone, either way you do it.
On the whole, I think I'd use the first method if I had the choice, but either
is doable. Just don't expect there to be any short-cuts ;-) This kind of
thing is never going to be less than tricky.

BTW, your follow-up post sounds as if you have a corrupted malloc() arena. It
would be worth your while (while you are developing this stuff) to use some
form of debugging version of your allocation library. Such things usually
exist and are worth tracking down since they can save you /huge/ amounts of
time.

-- chris
 
S

Stefan Schulz

If you keep it in the 'C' malloc arena (or similar) then you'll have to
manage allocation and deallocation yourself. If Java objects have some
kind of access to that data, then they will also have to take part in
that management, and that will not happen automatically. One way to
handle it would be to keep a reference count for each malloc()-ed 'C'
block and free() it only when that count drops to zero. You Java
objects will have to be careful (just as C code would be) to keep the
reference counts correct. You'll probably have to use finalisation (or
similar) to ensure that the 'C' reference counts are decremented when
Java objects are GCed.

Fairly complicated, and unfortunately rather error-pone, either way you
do it. On the whole, I think I'd use the first method if I had the
choice, but either is doable. Just don't expect there to be any
short-cuts ;-) This kind of thing is never going to be less than
tricky.

I would suggest you build a "Java Wrapper" around the native resource,
maybe something like this:

public abstract class PointerWrapper {
private final long ptr;

protected PointerWrapper(long ptr){
this.ptr = ptr;
}

public final long getPointer(){
if (freed){
throw new IllegalStateException();
}
}

public boolean isValid(){
return !freed;
}

public final void free(){
if (freed){
throw new IllegalStateException();
}

freed = true;
free(ptr);
}

protected final void finalize() throws Throwable {
free();
}
}}

If the resource may persist longer, you might even try making free()
private.

WARNING: This was written from memory. It may contain typos, or even
logical errors, but this is the general way i would go about things.
 
S

Stefan Schulz

If you keep it in the 'C' malloc arena (or similar) then you'll have to
manage allocation and deallocation yourself. If Java objects have some
kind of access to that data, then they will also have to take part in
that management, and that will not happen automatically. One way to
handle it would be to keep a reference count for each malloc()-ed 'C'
block and free() it only when that count drops to zero. You Java
objects will have to be careful (just as C code would be) to keep the
reference counts correct. You'll probably have to use finalisation (or
similar) to ensure that the 'C' reference counts are decremented when
Java objects are GCed.

Fairly complicated, and unfortunately rather error-pone, either way you
do it. On the whole, I think I'd use the first method if I had the
choice, but either is doable. Just don't expect there to be any
short-cuts ;-) This kind of thing is never going to be less than
tricky.

I would suggest you build a "Java Wrapper" around the native resource,
maybe something like this:

public abstract class PointerWrapper {
private final long ptr;

protected PointerWrapper(long ptr){
this.ptr = ptr;
}

public final long getPointer(){
if (freed){
throw new IllegalStateException();
}
}

public boolean isValid(){
return !freed;
}

public final void free(){
if (freed){
throw new IllegalStateException();
}

freed = true;
free(ptr);
}

protected final void finalize() throws Throwable {
free();
}

protected abstract void free(long pointer);
}}

If the resource may persist longer, you might even try making free()
private.

WARNING: This was written from memory. It may contain typos, or even
logical errors, but this is the general way i would go about things.
 
V

Vig

Stefan Schulz said:
I would suggest you build a "Java Wrapper" around the native resource,
maybe something like this:

public abstract class PointerWrapper {
private final long ptr;

protected PointerWrapper(long ptr){
this.ptr = ptr;
}

public final long getPointer(){
if (freed){
throw new IllegalStateException();
}
}

public boolean isValid(){
return !freed;
}

public final void free(){
if (freed){
throw new IllegalStateException();
}

freed = true;
free(ptr);
}

protected final void finalize() throws Throwable {
free();
}

protected abstract void free(long pointer);
}}

If the resource may persist longer, you might even try making free()
private.

WARNING: This was written from memory. It may contain typos, or even
logical errors, but this is the general way i would go about things.

Thanks
 
V

Vig

Chris Uppal said:
Vig said:
I need to get a C program to talk to Java and I am using JNI. I have
created a dll that the Java code loads. The C code reads from a file and
stores some data in the heap. I can get the dll to send data back and
forth to the Java code, but its not possible to free the variables
pointing to the heap since that data is reused several times.

I'm not sure what you mean.

Do you mean that you want to allocate stuff in the 'C' heap, have Java objects
"know" about that data, and have it somehow magically cleaned up for you
(perhaps by the Java GC) ? If so then that won't work.

I'm guessing at what you are trying to do here, so the following may be
inappropriate, irrelevant, Just Plain Wrong ;-) But..

First decide /where/ the data is gong to be stored.

If you keep it as Java byte[] arrays (or similar) then the Java GC can and will
look after it for you, but you'll probably have more complicated code to create
and fill in those arrays from the 'C' side.

If you keep it in the 'C' malloc arena (or similar) then you'll have to manage
allocation and deallocation yourself. If Java objects have some kind of access
to that data, then they will also have to take part in that management, and
that will not happen automatically. One way to handle it would be to keep a
reference count for each malloc()-ed 'C' block and free() it only when that
count drops to zero. You Java objects will have to be careful (just as C code
would be) to keep the reference counts correct. You'll probably have to use
finalisation (or similar) to ensure that the 'C' reference counts are
decremented when Java objects are GCed.

Fairly complicated, and unfortunately rather error-pone, either way you do it.
On the whole, I think I'd use the first method if I had the choice, but either
is doable. Just don't expect there to be any short-cuts ;-) This kind of
thing is never going to be less than tricky.

BTW, your follow-up post sounds as if you have a corrupted malloc() arena. It
would be worth your while (while you are developing this stuff) to use some
form of debugging version of your allocation library. Such things usually
exist and are worth tracking down since they can save you /huge/ amounts of
time.

It's not exactly what I would have loved to hear, but thanks a lot ... saved
me a lot of time with this...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top