jvm crash on reading arraylist from java class with jni - java

I have troubles reading an arraylist from a java class with jni. In the java class the arraylist is defined like this
public static List XTN_STC_search_result = new ArrayList();
The arraylist then gets filled with a string, a score value as double and an array of integers.
So the structure looks like this:
[
[label str 1, score value 1, [int 1, int 2, int n]],
[label str 2, score value 2, [int 1, int 2],
...
]
On the JNI C side i do the following to read that arraylist.
After reading the static field and get the object I go into the loop iterating over the array to read all values. All goes well, I can read every single arraylist entry, the label string, the double value and can access the array of integers with a nested loop. Within the nested loop if fetch the integer array entry with getObjectArrayElement and it seems to get that value. Afterwards I test it on NULL and it is not NULL. To be pedantic I I double check if that array entry (of the integer array) is an instance of Integer with isInstanceOf. That very call crashes my program with SIGSEGV and JVM bails out.
Below you see the code snippet of the problemtic area ...
int
XTN_ce_java_get_cluster(XTN_VM_IDX vm_idx) {
...
/* java result object , the arraylist to read */
jobjectArray result_obj;
/* result object array (element of result_obj) */
jobjectArray jv_result_object_array;
jint jv_result_object_array_size;
/* element to hold phrase, score and nested integer array */
jobject jv_object_array_cluster_elem;
jint jv_object_array_cluster_elem_size;
...
/* get arraylist */
jv_result_object_array = (*(Record.env))->GetObjectArrayElement(
Record.env, result_obj, 1 );
jv_result_object_array_size = (*(Record.env))->GetArrayLength(Record.env,
jv_result_object_array );
...
/* loop over arraylist entries */
for (i = 0; i < jv_result_object_array_size; i++) {
/* read label string */
if ( (*(Record.env))->IsInstanceOf(Record.env,
(jobject)jv_object_array_cluster_elem, classString)) {
...
} else if ( (*(Record.env))->IsInstanceOf(Record.env, jv_object_array_cluster_elem, classObject)) {
/* we are about to read the integer array from the arraylist ... */
/* get size of integer array */
jv_object_array_cluster_elem_size = (*(Record.env))->GetArrayLength(
Record.env, jv_object_array_cluster_elem);
/* this case should not happen, the integer array has a minimum entry of 1 element */
if (jv_object_array_cluster_elem_size <= 0)
continue;
for (j = 0; j < jv_object_array_cluster_elem_size; j++) {
/* get element from integer array */
jv_cluster_data_array_elem = (*(Record.env))->GetObjectArrayElement(
Record.env, jv_object_array_cluster_elem, j);
/* check if null */
if (jv_cluster_data_array_elem == NULL) {
break;
/* now check type */
/* THIS CALL CRASHES JVM */
if ( (*(Record.env))->IsInstanceOf(Record.env, jv_cluster_data_array_elem,
classInteger)) {
fprintf(stdout, "got array entry of type integer */
}
...
} /* inner loop integer array */
} /* outer loop object array */
return 1;
}
I do not understand why it crashes there, even though I seem not to be able to access that field for reading (with GetIntField() for example). If I leave out the isInstanceOf call (just looping over the integer array) all goes fine, it loops over the complete arraylist, reads my strings and doubles, loops over the nested integer array and finishes successfully. Honestly the
Does anybody have a hint for me where to look or what to improve? I hope the provided code snippet of the arraylist reader function is complete enough to understand my problem. Maybe somebody can point me to the right direction on this issue, hopefully :-))
I use
JRE version: 6.0_22-b04
Java VM: Java HotSpot(TM) 64-Bit Server VM (17.1-b03 mixed mode linux-amd64 )
on Ubuntu
Thanks so much in advance for helping me out on this.
Update 2010/12/06:
==================
As Peter suggested, I completely reworked the object reader function using the
Java methods of the object through the native interface. Additionally it
turned out, that I even do not need that very arraylist I constructed in
the Java class, I rather used and read the internal class Results Object
List directly and its object methods to read the results I need. So in short,
now it is more efficient and I was able to skip that Arraylist construction
completey and spare one processing step.
First I thought, using the Java methods of that very class through JNI would
give me a much higher response time, using Java methods through JNI is surely
not very fast (compared to using the Java methods in Java directly). Using JNI
as a bridge from C to Java costs performance and computing time. But anyway, I
figured out, I am about 200ms faster (using the same data set) than my old
reader method with the arraylist, so I even gained some performance.
Ok, to put it in short, using JNI and the Object methods of the Java class
spared me a lot of headache and the code now is much more readable.
Conclusion: I would like to encourage everybody that is facing a similar
problem using the Object methods of the class you work with through JNI.

The first thing to note is that ArrayList != an array. The methods you are using to access the arraylist only work for an array.
I suggest you access the ArrayList by calling the methods of the List just as you would in Java.

Related

Sorting an object array into another array based on a variable

I have a problem with a program I'm writing for a school assignment.
Essentially, before this piece of code, I already recieve and work with a bunch of information that I store into an array of objects. Now I have to sort this array (after it's sorted, I will have to calculate some things in the order of the PRIORITY variable).
presume I already have a MyClass[] array called input, that stores a finite amount of MyClass objects.
MyClass[] priorityArray = new MyClass[input.length];
for (int i=0; i<priorityArray.length; i++) {
int maxIndex = 0;
int maxPrivilege = input[i].returnPrivilege();
for (int j=1; j<input.legnth; j++) {
int currentPrivilege = input[j].returnPrivilege();
if (currentPrivilege > maxPrivilege) {
maxPrivilege = currentPrivilege;
maxIndex = j;
}
}
priorityArray[i] = input[maxIndex];
input[maxIndex].setPrivilege(-900000000);
}
the MyClass class if nothing fancy, but of course, contains a proper constructor, getter and setter methods and an integer variable "privilege".
I'm getting an error in my final tests of the program and, seeing as the program returns privileges as "-900000000", it has to have something to do with this part of the code.
It's also not even writing certain MyClass instances from the input array into the priorityArray array.
How can I clead this up? Help.
I'll rewrite my answer totally.
In this line
priorityArray[i] = input[maxIndex];
You are assigning object from one array to another array by reference. It means that there is only one object and you set value to -9000000 in the next line to it. Of course element in priorityArray will have the same changes. To fix it you need to clone your object here.

Inexplicable Array assignment behavior in Java

So here it goes. I've been building a piece of software for a bigger project, and right now, I am simply baffled by the way Java treats my code. I have absolutely no idea as to why Java behaves the way it does right here.
It seems to skip part of my code, and assigns values to a different array than I expected when no according method is called.
I have walked over this for a few hours now with the IntelliJ Debugger, inspecting everything ever so closely, but I have not found a single reason as to why things happen the way they do.
package com.whatareyoudoing.java;
import java.util.Arrays;
/**
* WHAT THE ACTUAL DUCK
*/
public class WTF {
private int[] number;
private int[] oldNumber;
public WTF() {
number = new int[1];
oldNumber = new int[1];
}
public void putNumber(int c) {
number[0] = c;
}
public void putOld() {
if(Arrays.equals(oldNumber, number)) {
System.out.println("Nothing to do!");
return; //How on earth can they literally be the same?!
}
oldNumber = number;
}
public void doWTF() {
putNumber(1);
putOld(); // Works.
putNumber(2); // Expected Result: number = 2; oldNumber = 1 [NOPE] number = 2; oldNumber = 2
putOld(); // [NOPE] Simply Skips with "Nothing to do"
putNumber(3); // Same odd behaviour
putOld(); // Aaaand skips again.
}
}
After calling putNumber the first time, using putNumber again simultaneously puts the value in both variables (oldNumber and Number) instead of only in number[0].
I continued to simplify my code as far as possible so this example is more hands-on. Obviously, the real example where I found this had arrays longer than a single element.
I also tested it with multidimensional arrays, as well as object arrays. No change in the behavior.
I am completely puzzled now and have absolutely no idea how to go on. If you can shed any light on this topic, please do so. I am more than confused.
The following assignment statement:
oldNumber = number;
makes oldNumber and number point to the same underlying array. Perhaps what you want is to make a copy:
System.arraycopy(number, 0, oldNumber, 0, number.length);
See the documentation for System.arraycopy for full details.
This line isn't doing what you think it's doing.
oldNumber = number;
It isn't copying the contents of one array to another. It is making the reference variable oldNumber refer to the same array object as number refers to.
oldNumber ----> [1]
number -------^
So, any change through either variable writes through to the same array, and the change is visible through both references, which refer to the same array.
Then later you call Arrays.equals with references to the same array, so they are "equal".
You want to copy the number with this line instead:
oldNumber[0] = number[0];
When you assign
oldNumber = number
you don't make a copy of the values in the array. oldNumber will point to the exact same array (and future changes in either variable reflect in the other).
You can make a copy with
oldNumber = Arrays.copyOf(number, number.length);
In the putOld function you assigned the reference of the first array to the other. After the first call oldNumber is a pointer to number and if you change a value in one, the other one is affected too.
If you want to copy the values System.arraycopy().

Select subarray without copying into new buffer?

I have float[] array of length 100. Is there a way I can select (pseudocode):
x = array[10:19];
To get elements 10,11,12,...,19 without copying over into another buffer? I'm in a mobile application where I don't want to waste space or time doing this. I'd rather just reference the pointers the system uses for array.
The most efficient way to do this would be to use System.arrayCopy(), which is much faster and more efficient than copying manually using a loop. It will require another array, but any approach you use (beyond just passing the original array around with a couple of ints representing the offset to use) will do this, and it's relatively cheap - the memory consuming bit is usually the objects that it's referencing rather than the array itself, and they are not copied.
No, there is no API to do that. The closest solution to this would be building your own class that wraps an existing array, and does the re-indexing:
class SubArray {
private final float[] data;
private final int offset;
private final int length;
public SubArray(float[] data, int offset, int length) {
this.data = data;
this.offset = offset;
this.length = length;
}
public float get(int index) {
if (index >= length) throw ...
return data[index + offset];
}
public void set(int index, float value) {
if (index >= length) throw ...
data[index + offset] = value;
}
}
If the result that you need is a new object that behaves like an array in all respects, including the indexing operator, you would need to make a copy.
(Update) Precondition: You should store the data in a Float[] instead of a float[], the performance-hit should be minimal.
You can use: Arrays.asList(array).subList(10, 20).
The Arrays.asList(array) does the following:
Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.) This method acts as bridge between array-based and collection-based APIs, in combination with Collection.toArray(). The returned list is serializable and implements RandomAccess.
Source
And then .subList(10, 20) returns you a List.
Then if you really want to work with arrays in the end, you could take the following lines:
List<Float> subList = Arrays.asList((Float[])array).subList(10, 20);
Float[] subArray = subList.toArray(new Float[subList.size()]);
(Update) Changed Arrays.asList(array) to Arrays.asList((Float[])array) such that it is correct now.
From documentation:
Returns an array containing all of the elements in this list in proper sequence (from first to last element); the runtime type of the returned array is that of the specified array. If the list fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this list.
If the list fits in the specified array with room to spare (i.e., the array has more elements than the list), the element in the array immediately following the end of the list is set to null. (This is useful in determining the length of the list only if the caller knows that the list does not contain any null elements.)
Like the toArray() method, this method acts as bridge between array-based and collection-based APIs. Further, this method allows precise control over the runtime type of the output array, and may, under certain circumstances, be used to save allocation costs.
Suppose x is a list known to contain only strings. The following code can be used to dump the list into a newly allocated array of String:
Source
This should ensure that no data is wasted, the only thing to be careful about could be autoboxing.
UPDATE: Changed my answer such that it now is correct under a precondition.
What is the problem of using a simple for loop? Objects are in java called by reference.
So, executing copying the array does not copy the objects.
float[] subarray = new float[10];
for(int i = 10, j = 0; i < 19; i++, j++) {
subarray[j] = x[i];
}
The array[0] is a reference to the object of x[0].
edit: This only applies for objects, and i don't know if it also applies to a float

Java: Counting instances in an object

I have the code:
int number;
for (Vartype var : dataset) {
number++;
}
This code does work, but var is never used. How else can this code be written so Java isn't complaining about an unused variable? "dataset" is an object.
Java's not complaining about the unused variable, your IDE is.
Instead of looping over each object in that array/Collection, you can just use its size to see how many elements are there.
// if dataset is an array:
int number = dataset.length;
// if dataset is a Collection:
int number = dataset.size();
The for-each as per your post will count the number of members in 'dataset' if it is a collection object.
You can also use for-loop for this.
or simply check the size of the object if it is a collection object.

What is inside code for array.length() in Java?

What is stored in 10th location of array
say
int[] array=new int[10];
Say we have values stored from array[0] to array[9], if I were to print elements without using
array.length()
or for (int a: array)
How do I proceed?
My basic question is how will JVM determine end of array, is it when a null is encountered parsing array or when a garbage value is encountered? what is inbuilt code of array.length() function?
What is stored in 10th location of array say
...
my basic question is how will JVM determine end of array, is it when a null is encountered parsing array or when a garbage value is encountered? what is inbuilt code of array.length() function?
Welcome C/C++ programmer :-)
Java uses a different paradigm than C/C++ for arrays. C/C++ uses the terminator/sentinel a.k.a. "garbage") value like NULL to indicate the end of the array. In Java, arrays are more like objects with a special "instance variable"-like variable length that indicates how many slots there are in the array. This special "instance variable" is set at the array's creation and is read-only. Its accessible by saying array.length.
Java expects the code to know when to stop at the end of the array by making sure they don't specify an index greater than length - 1. However, the JVM checks every access to the array for security reasons just in case. If the JVM finds an array index that is less than 0 or greater than length - 1, then the JVM throws an IndexOutOfBoundsException.
What is stored in 10th location of array
Since we can always check the length, there is no need for a marker at the end of the array in Java. There isn't anything special after the last item in the array (it likely will be some other variable's memory).
if I were to print elements without using array.length()
for(int a: array) {
// code of loop body here
}
This code is magically transformed by the compiler to:
for (int i = 0; i < array.length; i++) {
int a = array[i];
// code of loop body here
}
However, the i index variable isn't accessible to the user's code. This code still uses array.length implicitly.
Arrays are objects with a length field. While looping, Java loads the length field and compares the iterator against it.
See 10.7 Array Members in the JLS
Internally, the JVM can track the length of an array however it sees fit. There's actually a bytecode instruction called arraylength that the Java compiler emits whenever you try to get the length of an array, indicating that it's up to the JVM to determine the best way to track the length of an array.
Most implementations probably store arrays as a block of memory whose first entry is the length of the array and whose remaining elements are the actual array values. This allows the implementation to query the length of the array, along with any value in the array, in O(1). If the implementation wanted to, though, it could store the elements followed by a sentinel value (as you've suggested), but I don't believe that any implementations do this because the cost of looking up the length would be linear in the size of the array.
As for how the foreach loop works, the compiler translates that code into something like this:
for (int i = 0; i < arr.length; ++i) {
T arrayElem = arr[i];
/* ... do work here ... */
}
And finally, with regards as to what the 10th element of a 10-element array is, there's no guarantee that there's even an object at that location. The JVM could easily allocate space for the array in a way where there is no tenth element. Since you can't ever actually get this value in Java (it would throw an exception if you tried), there's no requirement that the JVM even have something meaningful there.
Hope this helps!
Define what a "garbage value" is. (Hint: since everything is binary, there is no such thing unless you use a sentinel value, and that's just bad practice).
The length of the array is stored inside the Array instance as a member variable. It's nothing complex.
In a comment on another, the OP writes:
I agree array.length is the conventional method, I was looking for any other option if available.
There is no other reasonable implementation option open to the JVM implementer ... on any mainstream hardware architecture.
In particular, the sentinel approach ONLY detects the case where an application fetches an array element one index beyond the end.
If it fetches 2 or more indexes beyond, then it misses the sentinel and proceeds to access memory whose contents are unknown.
If it stores, then the sentinel is not consulted.
If it needs to directly access the array size as part of the application algorithm, searching for a sentinel is a very inefficient way of doing it. (Not to mention unreliable; e.g. if null is a valid array element.)
Sentinels don't work for (most) primitive arrays because there is no value that can be used as a sentinel. (The idea of a primitive array holding a null is nonsensical from the JLS perspective, since null is not type compatible with any Java primitive type.)
The garbage collector needs an array length in all cases.
In short, the length has to be stored in the array to deal with the other cases. Storing a sentinel as well means you are wasting space storing redundant information, and CPU cycles creating the sentinel and copying it (in the GC).
Okay, here I go :-)
Ways to deal with "arrays" in C
In C there are numerous ways to deal with array. For the remainder I will talk about string* (and use the variable strings which has a type of string*). This is because t[] "effectively decomposes" into t* and char* is the type of a "C string". Thus string* represents a pointer to "C string". This glosses over a number of pedantic issues in C w.r.t. "arrays" and "pointers". (Remember: just because a pointer can be accessed as p[i] doesn't make the type an array in C parlance.)
Now, strings (of type string*) has no way to know it's size -- it only represents a pointer to some string, or NULL perhaps. Now, let's look at some of the ways we can "know" the size:
Use a sentinel value. In this I am assuming the use NULL as the sentinel value (or it might be -1 for an "array" of integers, etc.). Remember that C has no such requirement that arrays have a sentinel value so this approach, like the following two, is just convention.
string* p;
for (p = strings; p != NULL; p++) {
doStuff(*p);
}
Track the array size externally.
void display(int count, string* strings) {
for (int i = 0; i < count; i++) {
doStuff(strings[i]);
}
}
Bundle the "array" and the length together.
struct mystrarray_t {
int size;
string* strings;
}
void display(struct mystrarray_t arr) {
for (int i = 0; i < arr.size i++) {
doStuff(arr.strings[i]);
}
}
Java uses this last approach.
Every array object in Java has a fixed sized which can be accessed as arr.length. There is special byte-code magic to make this work (arrays are very magical in Java), but at the language level this is exposed as just a read-only integer field that never changes (remember, each array object has a fixed size). Compilers and the JVM/JIT can take advantage of this fact to optimize the loop.
Unlike C, Java guarantees that trying to access an index out of bounds will result in an Exception (for performance reasons, even if it were not exposed, this would require the JVM kept track of the length of each array). In C this is just undefined behavior. For instance, if the sentinel value wasn't within the object (read "the desired accessibly memory") then example #1 would have lead to a buffer-overflow.
However, there is nothing to prevent one from using sentinel values in Java. Unlike the C form with a sentinel value, this is also safe from IndexOutOfBoundExceptions (IOOB) because the length-guard is the ultimate limit. The sentinel is just a break-early.
// So we can add up to 2 extra names later
String names[] = { "Fred", "Barney", null, null };
// This uses a sentinel *and* is free of an over-run or IOB Exception
for (String n : names) {
if (n == null) {
break;
}
doStuff(n);
}
Or possibly allowing an IOOB Exception because we do something silly like ignore the fact that arrays know their length: (See comments wrt "performance").
// -- THERE IS NO EFFECTIVE PERFORMANCE GAIN --
// Can ONLY add 1 more name since sentinel now required to
// cleanly detect termination condition.
// Unlike C the behavior is still well-defined, just ill-behaving.
String names[] = { "Fred", "Barney", null, null };
for (int i = 0;; i++) {
String n = strings[i];
if (n == null) {
break;
}
doStuff(n);
}
On the other hand, I would discourage the use of such primitive code -- better to just use a suitable data-type such as a List in almost all cases.
Happy coding.
In terms of how you'd print all the elements in the array without using either a for each loop or the length field, well in all honesty you just wouldn't. You could potentially just have a for loop like the following:
try {
for(int i=0 ; ; i++) {
System.out.println(arr[i]);
}
}
catch(IndexOutOfBoundsException ex) {}
But that's an awful way to do things!
how will you print elements without using array.length or foreach loop
You could of course loop through the array without bounds checking and then catch (and swallow) the ArrayIndexOutOfBoundsException in the end:
try {
int i = 0;
while (true) {
System.out.println(arr[i++]);
}
catch (ArrayIndexOutOfBoundsException e) {
// so we are past the last array element...
}
This technically works, but it is bad practice. You should not use exceptions for flow control.
All array access outside the interval [0, 9] gives an ArrayIndexOutOfBoundsException, not only position 10. So, conceptually you could say that your whole memory (reaching with indexes from Integer.MIN_VALUE to Integer.MAX_VALUE) is filled with sentinel values, apart from the space of the array itself, and when reading or writing to a position filled with a sentinel, you get your exception. (And each array has its own whole memory to spend).
Of course, in reality no one has a whole memory for each array to spend, so the VM implements the array accesses a bit smarter. You can imagine something like this:
class Array<X> {
private final int length;
private final Class<X> componentType;
/**
* invoked on new X[len] .
*/
public Array<X>(int len, Class<X> type) {
if(len < 0) {
throw new NegativeArraySizeException("too small: " + len);
}
this.componentType = type;
this.len = len;
// TODO: allocate the memory
// initialize elements:
for (int i = 0; i < len; i++) {
setElement(i, null);
}
}
/**
* invoked on a.length
*/
public int length() {
return length;
}
/**
* invoked on a[i]
*/
public X getElement(int index) {
if(index < 0 || length <= index)
throw new ArrayIndexOutOfBoundsException("out of bounds: " + index);
// TODO: do the real memory access
return ...;
}
/**
* invoked on a[i] = x
*/
public X setElement(int index, X value) {
if(index < 0 || length <= index) {
throw new ArrayIndexOutOfBoundsException("out of bounds: " + index);
}
if(!componentType.isInstance(value)) {
throw new ArrayStoreException("value " + value + " is of type " +
value.getClass().getName() + ", but should be of type "
+ componentType.getName() + "!");
}
// TODO: do the real memory access
return value;
}
}
Of course, for primitive values the component type check is a bit simpler, since already the compiler (and then the VM bytecode verifier) checks that there are the right types, sometimes doing a type conversion, too. (And the initialization would be with the default value of the type, not null.)

Categories