Java – is there any way to create a basic array without initialization?

As we know, Java always initializes arrays at creation time That is, new int [1000000] always returns an array with all elements = 0 I understand that this is necessary for an object array, but for the original array (except maybe Boolean), in most cases, we don't care about the initial value

Does anyone know how to avoid this initialization?

Solution

I did some research There is no legal method to create uninitialized arrays in Java Even JNI newxarray creates an initialized array Therefore, it is impossible to accurately know the cost of zeroing the array But I made some measurements:

1) Creation of 1000 byte arrays with different array sizes

long t0 = System.currentTimeMillis();
        for(int i = 0; i < 1000; i++) {
//          byte[] a1 = new byte[1];
            byte[] a1 = new byte[1000000];
        }
        System.out.println(System.currentTimeMillis() - t0);

On my PC, byte [1] is 1ms and byte [1000000] is ~ 500 ms. it sounds impressive to me

2) We don't have a fast (native) method to fill arrays in JDK, arrays Fill is too slow, so let's look at 1000 copies of an array of at least 1000000 sizes with the native system arraycopy

byte[] a1 = new byte[1000000];
    byte[] a2 = new byte[1000000];
    for(int i = 0; i < 1000; i++) {
        System.arraycopy(a1,a2,1000000);
    }

It's 700 milliseconds

It gives me reason to believe that a) creating long arrays is expensive b) it seems expensive because of useless initialization

3) Let's sun misc. Unsafe http://www.javasourcecode.org/html/open-source/jdk/jdk-6u23/sun/misc/Unsafe.html. It is protected from external use, but not too much

Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe)f.get(null);

This is the cost of memory allocation testing

for(int i = 0; i < 1000; i++) {
        long m = u.allocateMemory(1000000);
    }

It needs < 1 ms, if you remember, 500 ms for new bytes [1000000] 4) Unsafe has no direct way to handle arrays It needs to know the class field, but the reflection does not display the field in the array There is not much information about the internal structure of the array. I think this is the specific of the JVM / platform However, like any other Java object, the header field is the same Looks like on my PC / JVM

header - 8 bytes
int length - 4 bytes
long bufferAddress - 8 bytes

Now, using unsafe, I will create byte [10], allocate a 10 byte memory buffer, and use it as my array element:

byte[] a = new byte[10];
    System.out.println(Arrays.toString(a));
    long mem = unsafe.allocateMemory(10);
    unsafe.putLong(a,12,mem);
    System.out.println(Arrays.toString(a));

It prints

[0,0]
[8,15,-114,24,0]

You can see that the data of the thay array is uninitialized

Now I'll change the length of our array (although it still points to 10 bytes of memory)

unsafe.putInt(a,8,1000000);
    System.out.println(a.length);

It shows 1000000 This is just to prove that the idea is effective

Now performance test I will create an empty byte array A1, allocate a 1000000 byte buffer, and allocate this buffer to a set of A1 length = 10000000

long t0 = System.currentTimeMillis();
    for(int i = 0; i < 1000; i++) {
        byte[] a1 = new byte[0];
        long mem1 = unsafe.allocateMemory(1000000);
        unsafe.putLong(a1,mem);
        unsafe.putInt(a1,1000000);
    }
    System.out.println(System.currentTimeMillis() - t0);

10ms is required

5) In C, there are malloc and alloc. Malloc only allocates memory blocks, and calloc initializes it with zero

CPP

...
JNIEXPORT void JNICALL Java_Test_malloc(jnienv *env,jobject obj,jint n) {
     malloc(n);
}

Java

private native static void malloc(int n);

for (int i = 0; i < 500; i++) {
    malloc(1000000);
}

Results malloc – 78 MS; calloc – 468 ms

conclusion

>It seems that Java array creation is slow because useless elements are zeroed. > We can't change it, but Oracle can There is no need to change anything in the JLS, just add the local method to Java lang.reflect. Array

public static native xxx [] newUninitialziedXxxArray(int size);

It is applicable to all original byte double and char types It can be used in JDK, just like in Java util. Same as in arrays

public static int[] copyOf(int[] original,int newLength) {
        int[] copy = Array.newUninitializedIntArray(newLength);
        System.arraycopy(original,copy,Math.min(original.length,newLength));
        ...

Or Java lang.String

public String concat(String str) {
        ...   
        char[] buf = Array.newUninitializedCharArray(count + otherLen);
        getChars(0,count,buf,0);
        ...
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>