Given this C++ Code:
void LoadData(char** myVar)
{
std:: string str("[Really Long String Here]");
unsigned int size = str.length() + 1;
*myVar = new char[size];
strncpy(*myVar, str.c_str(), size);
}
And this JNA Java:
Pointer myVar = new Memory(Pointer.SIZE);
this.Lib.LoadData(myVar);
this.someVar = myVar.getPointer(0).getString(0);
I'm having memory leaks, as I understand it, getPointer(0) should create a pointer object that should be released on finalize(), but it seems to not be.
Am I missing something? This seems up to spec... and I can run the function above with no leaks in C++ fine.
I call the Java code in a loop to test the leak, I've tried putting in pauses, and manually calling the GC, also it'll bloat to gigabytes rather quickly this way.
I've been banging my head against this for a few days now and it sucks to get hung up on something so trivial as attempting to free memory.As far as I can tell I can only manually free memory in Java if I have the address, but I can't see how I'd get that.
Edit:
Nevermind, I don't even think there is a way to do manually free through JNA without extending it...
Add this function to the C++ library...
void FreeData(char** myVar)
{
delete [] *myVar;
}
And then make this the JNA code
Pointer myVar = new Memory(Pointer.SIZE);
this.Lib.LoadData(myVar);
this.someVar = myVar.getPointer(0).getString(0);
this.Lib.FreeData(myVar);
This way you allocate and delete the memory in C++.
Allocate in the caller, not the callee.
For example:
int LoadData(char* buf, int maxlen) {
std:: string str("[Really Long String Here]");
strncpy(buf, str.c_str(), maxlen);
if (str.length() < maxlen)
return str.length();
return maxlen;
}
Then when you call from Java, pass in a byte[] of the appropriate size. Note that this implementation is potentially very inefficient, but the idea is that you don't generally want to be allocating memory in one context and deallocating it in another.
Instead of
myVar = new char[size]
use
*myVar = malloc(size);
strncpy(*myVar, str.c_str(), size);
Arrays need to be deleted like:
delete [] *myVar;
JNA prolly doesn't know to do that.
Related
I am starting to use JNA to communicate with a device on the RS485 interface of a computer. Suprisingly to me I came to good results very quickly. But now I am stuck by a simple problem. The library I use accepts a pointer to a pointer of struct. The actual signature is
func(Struct1 **, Struct2 **, Struct3 *, Struct4 *, long)
Now to indicate the size of the first parameter the library expects the last pointer to be a NULL pointer. This is what fails. Following code is what I tried so far:
Struct1.ByReference[] s = (Struct1.ByReference[]) new Struct1.ByReference().toArray(size);
int pos = 0;
// ...
// for loop to set the s[pos] struture values
for(pos = 0; pos < size - 1; pos++)
// ...
// Now set the last array element to a null pointer to indicate end-of-list
s[pos].getPointer().setPointer(0, null);// Following does not work: results in zero memoried structure
s[pos] = null; // Following does not work wither: NullPointerException at com.sun.jna.Structure.autoWrite
EDIT 1
s[pos] = new Struct1.ByReference(Pointer.NULL); // results in zero memoried structure as well
EDIT 2
According to technomage's question. If I were to write C code it would probably look something like that:
Struct1 **s = malloc(n * sizeof(Struct1*));
for(int i=0; i<n; i++)
{
if(i == n -1)
{
s[i] = NULL;
}
else
{
s[i] = malloc(sizeof(Struct1));
s[i].bla = value;
....
}
}
But be warned: I am not very skilled in C/C++. I consider Java to be my domain.
Has anyone had a similar problem? Maybe I am just not seeing the wood for the trees...
Thanks in advance.
Structures in JNA are pointers, so what you really need here is a pointer to a (pointer to a) Structure, which is a PointerByReference -- in your case, an array of them.
Given the code example above, you'll create your array of Structures, one less than n:
Struct1[] struct1Array = new Struct1[n-1];
This only allocates the Java memory for the array.
Next you'll instantiate and write the changes you make to native memory:
for (int i = 0; i < n-1; i++) {
struct1Array[i] = new Struct1();
struct1Array[i].bla = value;
struct1Array[i].write();
}
The new Struct1() allocates native side memory for these structures. It's possible to use the Structure.toArray() method to do this as well; I'm intentionally doing this a bit more manual and low-level to try to make clear what's happening.
Then you'll create a corresponding PointerByReference array to hold the pointers to these structures. You'll add an extra element for the null:
PointerByReference[] pbrArray = new PointerByReference[n];
Again, this is only java-side allocation. And then you fill it with pointers to the pointers to the structure, obtained from the Structure.getPointer() method:
for (int i = 0; i < n-1; i++) {
pbrArray[i] = new PointerByReference(struct1Array[i].getPointer());
}
pbrArray[n - 1] = new PointerByReference(Pointer.NULL);
The new PointerByReference() here allocates the native side memory for the pointer itself, which points to the native-side structure you allocated earlier.
From how I understand your initial question, you will pass this PointerByReference array to your function, which presumably updates your structures.
Since you created the two arrays in this fashion, you can keep track of their correspondence by array index. You may have to iterate through the structure array and read() the native memory into the Java-side structure to do further processing with it. Typically when you work directly with Structures being passed to methods they autowrite and autoread, but when using a PointerByReference to indirectly reference the Structure, JNA isn't as friendly.
As an alternative to tracking the two arrays by corresponding indices, you could "forget" the initial Structure assignment and recover it later using the PointerByReference.getValue() method on your array to recover a pointer to the memory for the structure, and then instantiate a new structure using that Pointer in its constructor (e.g. new Struct1(pbr.getValue()) which calls super() with that pointer).
I want to access to a char[] from JNI code, avoiding if possible a copy. For now, here is what I do :
void my_function(JNIEnv *env, jcharArray array) {
jsize len = env->GetArrayLength(array);
if (env->ExceptionCheck() == JNI_TRUE)
return;
jchar *chars = env->GetPrimitiveArrayCritical(array);
// process chars and len
env->ReleasePrimitiveArrayCritical(array, chars, JNI_ABORT);
}
According to JNI documentation, GetPrimitiveArrayCritical may return NULL when an OOM exception was "thrown". However they do not tell explicitly if ReleasePrimitiveArrayCritical should be still called in that situation.
Should I do
jchar *chars = env->GetPrimitiveArrayCritical(array);
if (chars == NULL)
return;
or
jchar *chars = env->GetPrimitiveArrayCritical(array);
if (chars != NULL) {
// process chars
}
env->ReleasePrimitiveArrayCritical(array, chars, JNI_ABORT);
ReleasePrimitiveArrayCritical(…, NULL, …) will fail. But I must confess that I never experienced GetPrimitiveArrayCritical() to return NULL. It's a pity there is no way to ask for the bytes conditionally, i.e. no JNI function GetPrimitiveArrayCriticalNoCopyOrFail()!
My understanding of docs is that, there is nothing to release, if you don't get your "chars". By calling release, you don't release your "array", just elements associated with the array. It frees "chars" if necessary (only if it is a copy)
Releasing "array" is necessary if you are the owner of it. In this case:
{code}
int len = 10;
jcharArray array = env->NewCharArray(len);
if (!array) return;
jchar* chars = env->GetCharArrayElements(array, NULL);
if (!chars) { env->DeleteLocalRef(array); return; }
{... do something...}
env->ReleaseCharArrayElements(array, chars, JNI_ABORT);
env->DeleteLocalRef(array);
Also, I found this sample of production code which explicitly calls to ReleasePrimitiveArrayCritical only if the returned pointer is not null.
https://code.google.com/p/chromium/codesearch#chromium/src/third_party/libjpeg_turbo/turbojpeg-jni.c&q=GetPrimitiveArrayCritical&sq=package:chromium&l=365
Looking at openjdk code, it seems that the call to ReleasePrimitiveArrayCritical is necessary to unlock the GC (GC_locker::unlock_critical) that was locked in the GetPrimitiveArrayCritical call.
Seems also that java array and native array arguments are ignored, and that GetPrimitiveArrayCritical never returns NULL anyway.
This is valid for openjdk 7 only though.
I'm using a C++ DLL via JNA.
I want to call the following method in Java, which writes into szVisor information that I want to read.
long FAR PASCAL DLL_GetLocalPortTS(char* szEquip,char* szVisor){
...
}
The Java interface implementation is the following:
public interface IE2E extends Library {
// Instancia de la dll, carga la librería
IE2E INSTANCE = (IE2E) Native.loadLibrary("e2e", IE2E.class);
...
int GetLocalPortTS(String equip, String[] equipInfo);
}
And the method call:
String equip = "equipID";
String equipInfo = "";
String[] rEquipInfo = {equipInfo};
IE2E sdll = IE2E.INSTANCE;
int ret = sdll.GetLocalPortTS(equip, rEquipInfo);
This execution nets me a fatal error in the JRE, but if I put both arguments as either String or String[] it doesn't. However, if I use both Strings it doesnt overwrite equipInfo and I don't get the info which I want; if I use both as arrays, the method doesn't get the equip value and doesn't operate.
Any insight on this will be welcome.
The problem is that the C code wants to write into szVisor, right? I guess it does something like this:
long GetLocalPortTS(char* szEquip,char* szVisor){
strcpy(szVisor, "I am C code result :)");
return 0;
}
If you pass in a String from the Java side, then the memory is owned by the JVM, so writing to it causes a crash. What you need is a Memory object, which is a wrapped malloc'd bit of memory that the C code can safely write to.
Your new JNA interface would be as follows. I've commented out the old version so you can compare:
public interface IE2E extends Library {
IE2E INSTANCE = (IE2E) Native.loadLibrary("e2e", IE2E.class);
//int GetLocalPortTS(String equip, String[] equipInfo);
int GetLocalPortTS(String equip, Memory equipInfo);
}
And the code to call it would be as follows, the 256 is a placeholder. Make sure you allocate enough to write the string to:
String equip = "equipID";
String equipInfo = "";
//String[] rEquipInfo = {equipInfo};
Memory rEquipInfo = new Memory(256);
IE2E sdll = IE2E.INSTANCE;
int ret = sdll.GetLocalPortTS(equip, rEquipInfo);
To use the result as a String, you'd do this:
rEquipInfo.getString(0);
As the documentation says, the Memory's finalize() method automatically calls free on the malloc'd memory so there's no need to worry about memory leaks.
I'm creating a StringBuilder to collect strings that I periodically flush to a server. If the flush fails, I want to keep the strings to try again next time, although in the mean time I might get additional strings to send which must be added to the StringBuilder.
What I want to know is what the most efficient way to do this would be, as this is being done in an Android app where battery usage and thus CPU usage is a big concern. Does calling StringBuilder's toString() function store the resulting string it returns internally so that a subsequent call doesn't have to do the work of copying all the original strings over? Or if the call fails, should I create a new StringBuilder initialized with the return value from toString()?
Here is the OpenJDK source code for StringBuilder:
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
The source for the String constructor with those parameters is:
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.offset = 0;
this.count = count;
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
So yes, it does create a new String everytime, and yes, it makes a copy of the char[] everytime.
It's important to note that this is one implementation of toString, and another implementation may obviously be different.
It would be an implementation detail. Since java strings are immutable a correct impl can choose to share or create new strings from StringBuilder.toString() even if it's not needed.
As everyone says, you can test to see if this is indeed a real performance issue for you. If it is one (clunky) workaround is to wrap StringBuilder and cache the resulting string. You can use a dirty flag to indicate the content was modified.
StringBuilder.toString API says that a new String object is allocated and initialized to contain the character sequence currently represented by this object.
What is an easy way to cause a heap overflow in Java? I need to test how some external code responds when memory goes away.
Simpler than adding elements to an array list imho is to just cut out the middleman:
public static void main(String[] args) {
int[] a = new int[Integer.MAX_VALUE];
}
Well theoretically not guaranteed to lead to a OoME but since the arraylist uses an array internally itself, the same limitations apply to the other solutions as well..
If all you want is an OutOfMemoryError
throw new OutOfMemoryError();
note: int[] a = new int[Integer.MAX_VALUE]; will only throw an OOME if you have less than 8 GB of heap free.
ArrayList<String> heapme = new ArrayList<String>();
while ( true ) {
heapme.add( "I WANT TO HEAP MY VIRTUAL MACHINE TO DEATH PLZ!!! K THNX BIE!!!!" );
}
Create an ArrayList, and add objects to it:
private static final List<String> list = new ArrayList<String>();
// ...
while(true) list.add("Hello World");
and, BTW, it's called a Memory Leak. OutOfMemoryError will be thrown.
Moreover, if you want a StackOverflow, you can do it with an infinite recursive method:
public void Foo(){Foo();}
StackOverflowError will be thrown.