How to deal with large arrays in Java [closed] - java

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
I am reading a file that has 10,000 int values and then trying to store these in an array. There is an exception thrown which says that the array value is too large.
I was wondering, rather than write this array out in to a variable, could i possibly just keep it in memory and read it from there. Would this be a suitable way of solving this problem?
edit:
After more examination it appears that the error being thrown is a "code to large for try statement" error. I am reading each array element and appending it to a string, maybe this is what is causing the error?

You could use an ArrayList instead - but an array should be fine with 10,000 values. Can you post more detail? Code, full stack trace etc. Theoretically it should be fine with Integer.MAX_VALUE elements (a LOT more than 10k), but of course you may run out of memory first!
In terms of "just keep it in memory and read it from there", well variables are just kept in memory, so whether you use an array or a list (or any other data structure) you'll always be reading it from memory!
EDIT: Based on your additional explanation then it's not a problem with the array size at all, it's a problem with you generating 10,000 lines of code to put in a single block, which is too many and thus it complains. Alter your code to generate code that uses a loop instead and all should be well, however many elements you have in there (up to Integer.MAX_VALUE of course.)

An array of 10,000 int values is about 40KB.
You could try to reduce the memory used further however I suspect this is not your problem.
Can you give us the actual error message? An array value is only too large if its a long e.g. say you used File.length()/4 to determine the size of the array, in which case you need to cast it to an int

It is strange that you cannot create 10000 elements long array. I believe that your problem is not the array length but the value of particular array element. Anyway if you need bigger arrays use Lists instead. Specifically java.util.LinkedList.

Your problem is that you are writing each array or String assignment out in full, something like this:
array[0] = 0;
array[1] = 1;
array[2] = 2;
// all the way up to 9999!
or this:
String s = "";
s += array[0];
s += array[1];
s += array[2];
// all the way up to 9999!
instead of in a loop. So you generate more code than Java will allow in a method.
This results in a compilation error as you describe:
$ javac Test.java
Test.java:7: code too large for try statement
try {
^
Test.java:4: code too large
public static void main(String[] args) {
^
2 errors
Following from discussion in comments, the code that you say is producing this compiler error does not have an enormous number of lines. Something doesn't make sense - the error you report does not line up with the code you say is causing it. At this late stage I strongly recommend that you post some code, and the error so that others can try to understand what might be causing this.
(Also, your question isn't likely to get much attention because you have accepted an answer. You might want to reconsider that if your question is not in fact answered.)

An array of 10,000 ints isn't very big at all. I can't think why you would have a problem keeping the data in memory (ie assigned to a variable).

I find it odd that 10,000 ints takes up too much memory. It could be that other stuff if eating up your memory. Have you tried increasing the available memory to Java? (i.e.-Xmx512m). If this is not possible, you can always try to use shorts or bytes if the numbers are small enough.
The array will take just as much space as chunk of memory (like c does).

This is a known bug in the JVM. It prohibits you from creating an array of integers with size 10,000 (and also 16,384 on Mac OS X). It has to do with the way in which Java translates the byte code into machine code. Changing the size of the array to 10,001 will solve the problem.

Related

What happens when a Java String overflows?

As far as I understand, Java Strings are just an array of characters, with the maximum length being an integer value.
If I understand this answer correctly, it is possible to cause an overflow with a String - albeit in "unusual circumstances".
Since Java Strings are based on char arrays and Java automatically checks array bounds, buffer overflows are only possible in unusual scenarios:
If you call native code via JNI
In the JVM itself (usually written in C++)
The interpreter or JIT compiler does not work correctly (Java bytecode mandated bounds checks)
Correct me if I'm wrong, but I believe this means that you can write outside the bounds of the array, without triggering the ArrayIndexOutOfBounds (or similar) exception.
I've encountered issues in C++ with buffer overflows, and I can find plenty of advice about other languages, but none specifically answering what would happen if you caused a buffer overflow with a String (or any other array type) in Java.
I know that Java Strings are bounds-checked, and can't be overflowed by native Java code alone (unless issues are present in the compiler or JVM, as per points 2 and 3 above), but the first point implies that it is technically possible to get a char[] into an... undesirable position.
Given this, I have two specific questions about the behaviour of such issues in Java, assuming the above is correct:
If a String can overflow, what happens when it does?
What would the implications of this behaviour be?
Thanks in advance.
To answer you first question, I had the luck of actually causing a error of such, and the execution just stopped throwing one of these errors:
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
So that was my case, I don't know if that represents a security problem as buffer overflow in C and C++.
A String in Java is immutable, so once created there is no writing to the underlying array of char or array of byte (it depends on the Java version and contents of the String whether one or the other is used). Ok, using JNI could circumvent that, but with pure Java, it is impossible to leave the bounds of the array without causing an ArrayOutOfBoundsException or alike.
The only way to cause a kind of an overflow in the context of String handling would be to create a new String that is too long. Make sure that your JVM will have enough heap (around 36 GB), create a char array of Integer.MAX_VALUE - 1, populate that appropriately, call new String( byte [] ) with that array, and then execute
var string = string.concat( new String( array ) );
But the result is just an exception telling you that it was attempted to create a too large array.

General query about efficiency

I'm relatively new to Java, having taken my first class in it little under a year ago, and I have a question regarding efficiency. I know that
Random rng = new Random();
int num = rng.nextInt(101);
System.out.println("Random number is: " + num); //Example 1
and
Random rng = new Random();
System.out.println("Random number is: " + rng.nextInt(101)); //Example 2
are equivalent. However my question is which is faster to calculate? In my mind, the first example stores a variable, which takes up RAM. The second example doesn't store anything, but has to calculate a lot more things whilst printing than the first example.
In my computing classes, I was taught that information coming from the CPU's internal registers is a lot faster than information coming from the RAM. Does that mean example 2 is technically more efficient for not having stored the number variable before printing it?
I'm of course assuming I will not need the randomly generated number at another point in the program.
Thank you for any and all help :)
Kind regards
Any sane compiler will be able to perform such compile time optimizations to reduce extra lines of code which are there to improve readability.That is not specific to Java(where JIT takes the optimizations to the next level)
Since the number is going to be converted to a String for the concatenation, it will probably be put in memory on the stack anyways.

Can Java skip .toUpperCase() on literal string constants already in upper case?

I have a .toUpperCase() happening in a tight loop and have profiled and shown it is impacting application performance. Annoying thing is it's being called on strings already in capital letters. I'm considering just dropping the call to .toUpperCase() but this makes my code less safe for future use.
This level of Java performance optimization is past my experience thus far. Is there any way to do a pre-compilation, set an annotation, etc. to skip the call to toUpperCase on already upper case strings?
What you need to do if you can is call .toUpperCase() on the string once, and store it so that when you go through the loop you won't have to do it each time.
I don't believe there is a pre-compilation situation - you can't know in advance what data the code will be handling. If anyone can correct me on this, it's be pretty awesome.
If you post some example code, I'd be able to help a lot more - it really depends on what kind of access you have to the data before you get to the loop. If your loop is actually doing the data access (e.g., reading from a file) and you don't have control over where those files come from, your hands are a lot more tied than if the data is hardcoded.
Any many cases there's an easy answer, but in some, there's not much you can do.
You can try equalsIgnoreCase, too. It doesn't make a new string.
No you cannot do this using an annotation or pre-compilation because your input is given during the runtime and the annotation and pre-compilation are compile time constructions.
If you would have known the input in advance then you could simply convert it to uppercase before running the application, i.e. before you compile your application.
Note that there are many ways to optimize string handling but without more information we cannot give you any tailor made solution.
You can write a simple function isUpperCase(String) and call it before calling toUpperCase():
if (!isUpperCase(s)) {
s = s.toUpperCase()
}
It might be not significantly faster but at least this way less garbage will be created. If a majority of the strings in your input are already upper case this is very valid optimization.
isUpperCase function will look roughly like this:
boolean isUpperCase(String s) {
for (int i = 0; i < s.length; i++) {
if (Character.isLowerCase(s.charAt(i)) {
return false;
}
}
return true;
}
you need to do an if statement that conditions those letters out of it. the ideas good just have a condition. Then work with ascii codes so convert it using (int) then find the ascii numbers for uppercase which i have no idea what it is, and then continue saying if ascii whatever is true then ignore this section or if its for specific letters in a line then ignore it for charAt(i)
sorry its a rough explanation

Java compiler error: lookup table exceeds 65535 limit

I'm running into this compiler error due to my extremely large lookup table based on this definition:
//92 X 182 array
private static final double[][] lookUpTable = new double[][]
{
{ numbers....}
};
As i understand it, dividing it up is a solution, but it would be extremely difficult to split this array up accurately. I also believe i could move it out to a file, but i don't know if i could format it in a way to help me, plus i don't want file reads every second.
Are there any other suggestions to help me get around this?
Convert your table to a file, embed the file as a resource, read it once in a static initialization block, and store it in a lookUpTable array. It will not be distinguishable from an array initialized through an aggregate, except there would be no 65535 limit. Storing in a static variable will help you avoid "reads every second".
As far as the format is concerned, you can put each row of the matrix in a separate line of the resource file. Reading and maintaining this file would be simple, because there would be no other mark-up around your numbers.
Here is a link to an answer explaining how to read a file from a resource.
Read the file once on demand.
As you have a table/matrix, I suggest having one line per row. Read each line and split the numbers and parse them individually.
You could keep the rows in a string (thus reducing the number of objects for java to handle) as comma separated values, and on program start, split each row and so build up your table of longs.

What is the max. capacity of byte-Array?

I made a JavaClass which is making addition, sub, mult. etc.
And the numbers are like (155^199 [+,-,,/] 555^669 [+,-,,/] ..... [+,-,*,/] x^n);
each number is stored in Byte-Array and byte-Array can contain max. 66.442
example:
(byte) array = [1][0] + [9][0] = [1][0][0]
(byte) array = [9][0] * [9][0] = [1][8][0][0]
My Class file is not working if the number is bigger then (example: 999^999)
How i can solve this problem to make addition between much bigger numbers?
When the byte-Array reachs the 66.443 values, VM gives this error:
Caused by: java.lang.ClassNotFoundException. which is actually not the correct error-description.
well it means, if i have a byte-array with 66.443 values, the class cannot read correctly.
Solved:
Used multidimensional-Byte Array to solve this problem.
array{array, ... nth-array} [+, -, /] nth-array{array, ... nth-array}
only few seconds to make an addition between big numbers.
Thank you!
A single method in Java is limited to 64KB of byte code. When you initialise an array in code it uses byte code to do this. This would limit the maximum size you can define an array to about this size.
If you have a large byte array of value I suggest you store it in an external file and load it at runtime. This way you can have a byte array of up to 2 GB. If you need more than this you need to have an array of arrays.
What does your actual code look like? What error are you getting?
A Java byte array can hold up to 2^31-1 values, if there is that much contiguous memory available.
Each array can hold a maximum of Integer.MAX_VALUE values. If it crashes, I guess you see an OutOfMemoryError. Fix that by starting you java vm with more heap space:
java -Xmx1024M <...>
(example give 1024 MByte heap space)
java.lang.ClassNotFoundException is thrown if the virtual machine needs a class and can't load it - usually because it is not on the class path (sometimes the case when we simply forget to compile a java source file..). This exception is totally unrelated to java array operations.
To continue the discussion in the comments section:
The name of the missing class is very important. At the line of code, where the exception is thrown, the VM tries to load the class ClassBigMath for the very first time and fails. The classloader can't find a file ClassBigMath.class on the classpath.
Double check first if the compiled java file is really present and double check that you don't have a typo in your source code. Typical reasons for this error:
We simply forget to compile a source file
A class file is on the classpath at compilation time but not at execution time
We do a Class.forName("MyClass") and have a typo in the class name
java.math.BigInteger is much better solution to handle large number. Is there any reason , you have choosed byte array ?
The maximum size of an array in Java is given by Integer.MAX_VALUE. This is 2^31-1 elements. You might get OOM exceptions for less if there is not enough memory free. Besides that, for what you are doing you might want to look at the BigInteger class. It seems you are doing your math in some form of decimal representation, which is not very memory efficient.

Categories

Resources