Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid initialization of a large array

Tags:

java

arrays

I allocate a large array of doubles as

double[] x = new double[ n ];

where n is large, and I want to avoid initialization to save time. Is it possible?

like image 911
user1325206 Avatar asked Apr 10 '12 22:04

user1325206


People also ask

How can use array without initializing in Java?

Declaring an array does not initialize it. In order to store values in the array, we must initialize it first, the syntax of which is as follows: datatype [ ] arrayName = new datatype [size];

What is a good way to initialize all the elements of a large array with the same value?

Macros: For initializing a huge array with the same value we can use macros. Using For Loop: We can also use for loop to initialize an array with the same value.

What is the correct way of initialization of array?

The initializer for an array is a comma-separated list of constant expressions enclosed in braces ( { } ). The initializer is preceded by an equal sign ( = ). You do not need to initialize all elements in an array.

How do you initialize an array of a certain size in Java?

Array Initialization in Java To use the array, we can initialize it with the new keyword, followed by the data type of our array, and rectangular brackets containing its size: int[] intArray = new int[10]; This allocates the memory for an array of size 10 .


2 Answers

Short answer: No. Arrays always get zeroed out when they are created.

If your profiling has shown this to be a major bottleneck, you could consider keeping a pool of array instances, with the length of each set to bigger than n will ever be. The problem would be that you then probably need a wrapper object to contain the data array and the actual length that is used, since you can no longer use data.length.

like image 72
Russell Zahniser Avatar answered Oct 15 '22 06:10

Russell Zahniser


** WARNING ** UNSAFE ALTERNATIVE **

It's not an exact solution, but it could be a viable alternative. This method has some risks. But you might go this route if it's really absolutely necessary. This method is using an undocumented sun.misc.Unsafe class to allocate off-heap memory to store the double values. Off-heap meaning it's not garbage-collected, so you'll need to take care to deallocate the associated memory.

The following code is based on this blog post about sun.misc.Unsafe.

import java.lang.reflect.Field;

import sun.misc.Unsafe;

@SuppressWarnings("restriction")
public class SuperDoubleArray {

    private final static Unsafe unsafe = getUnsafe();
    private final static int INDEX_SCALE = 8;

    private long size;
    private long address;

    public SuperDoubleArray(long size) {
        this.size = size;
        address = unsafe.allocateMemory(size * INDEX_SCALE);
    }

    private static Unsafe getUnsafe() {
        try {
            Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
            singleoneInstanceField.setAccessible(true);
            return (Unsafe) singleoneInstanceField.get(null);
        } catch (IllegalArgumentException | SecurityException 
                | NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public void set(long i, double value) {
        unsafe.putDouble(address + i * INDEX_SCALE, value);
    }

    public double get(long idx) {
        return unsafe.getDouble(address + idx * INDEX_SCALE);
    }

    public long size() {
        return size;
    }

    public void deallocate() {
        unsafe.freeMemory(address);
    }

}

The following code will print some random double values coming from the unitialized memory.

SuperDoubleArray sda = new SuperDoubleArray(100);
for (int i=0; i<sda.size(); i++) {
    System.out.println(sda.get(i));
}
sda.deallocate();

There are no safety/range-checks, no nothing, you can easily crash the JVM with it, might not work with non-SUN JREs, might even stop working in future SUN JRE versions, but it might be the only solution in some cases. It can also allocate > Integer.MAX_VALUE sized pseudoarrays, unlike Java arrays.

java.nio.ByteBuffer.allocateDirect(...) actually uses the same Unsafe class behind the scenes to allocate byte buffers, and you could use ByteBuffer.allocateDirect(8*size).asDoubleBuffer() to adapt it to a DoubleBuffer, but ByteBuffer.allocateDirect(...) is still initializing the buffer with zeroes, so it might have a performance overhead.

like image 26
Nándor Előd Fekete Avatar answered Oct 15 '22 04:10

Nándor Előd Fekete