加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 有没有办法创建一个基本的数组没有初始化?

发布时间:2020-12-14 05:51:42 所属栏目:Java 来源:网络整理
导读:我们知道,Java总是在创建时初始化数组.即new int [1000000]总是返回一个所有元素= 0的数组.我明白这是Object数组必须的,但是对于原始数组(除了可能是Boolean),在大多数情况下我们不关心初始值. 有没有人知道避免这种初始化的方法? 解决方法 我做了一些调查.
我们知道,Java总是在创建时初始化数组.即new int [1000000]总是返回一个所有元素= 0的数组.我明白这是Object数组必须的,但是对于原始数组(除了可能是Boolean),在大多数情况下我们不关心初始值.

有没有人知道避免这种初始化的方法?

解决方法

我做了一些调查.在Java中创建未初始化的数组没有合法的方法.即使JNI NewXxxArray也创建了初始化的数组.因此,不可能准确地知道阵列归零的成本.不过我做了一些测量:

1)具有不同数组大小的1000字节数组创建

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);

在我的PC上,字节[1]为1ms,字节[1000000]为?500 ms.听起来令我印象深刻

2)我们在JDK中没有一个快速(本机)方法来填充数组,Arrays.fill太慢了,所以让我们看看至少有1,000,000个大小的数组的1000次拷贝与本机的System.arraycopy

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

是700毫秒

它给我理由相信a)创建长阵列是昂贵的b)它似乎是昂贵的,因为无用的初始化.

3)让我们来sun.misc.Unsafe http://www.javasourcecode.org/html/open-source/jdk/jdk-6u23/sun/misc/Unsafe.html.它受到外部使用的保护,但不要太多

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

这是内存分配测试的成本

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

它需要< 1 ms,如果你还记得,对于新的字节[1000000],需要500ms. 4)Unsafe没有直接的方法来处理数组.它需要知道类字段,但反射在数组中不显示字段.关于数组内部结构没有太多的信息,我想这是JVM /平台的具体.然而,像其他任何Java对象一样,头域也是如此.在我的PC / JVM上看起来像

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

现在,使用Unsafe,我将创建byte [10],分配一个10字节的内存缓冲区,并将其用作我的数组元素:

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));

它打印

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

您可以看到thay数组的数据未初始化.

现在我将更改我们的数组长度(尽管它仍然指向10字节内存)

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

它显示1000000.这只是为了证明这个想法是有效的.

现在性能测试.我将创建一个空字节数组a1,分配一个1000000字节的缓冲区,将这个缓冲区分配给a1一组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.

5)在C中有malloc和alloc,malloc只是分配内存块,calloc也用零初始化它.

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);
}

结果malloc – 78 ms; calloc – 468 ms

结论

>似乎Java数组创建速度很慢,因为无用的元素归零.
>我们不能改变它,但Oracle可以.不需要更改JLS中的任何内容,只需将本地方法添加到java.lang.reflect.Array中即可

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

适用于所有原始数字类型(byte-double)和char类型.它可以在JDK中使用,就像在java.util.Arrays中一样

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

或java.lang.String

public String concat(String str) {
        ...   
        char[] buf = Array.newUninitializedCharArray(count + otherLen);
        getChars(0,count,buf,0);
        ...

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读