我已经做了一些调查。没有合法的方法在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]给出了<1毫秒,对于字节[1000000]给出了〜500毫秒。听起来对我印象深刻。
2)JDK中没有用于填充数组的快速(本机)方法,Arrays.fill太慢,因此让我们至少看看本机System.arraycopy可以对1000万个大小的数组进行1000次复制。
byte[] a1 = new byte[1000000]; byte[] a2 = new byte[1000000]; for(int i = 0; i < 1000; i++) { System.arraycopy(a1, 0, a2, 0, 1000000); }
这是700毫秒。
这使我有理由相信a)创建长数组是昂贵的b)由于无用的初始化,它似乎是昂贵的。
3)让我们来看看sun.misc.Unsafe http://www.javasourcepre.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); }
如果您还记得的话,新字节[1000000]花费的时间少于1毫秒,花费了500毫秒。
4)不安全的方法没有直接使用数组的方法。它需要知道类字段,但是反射不显示数组中的任何字段。关于数组内部的信息不多,我想这是特定于JVM
/平台的。但是,它像其他Java对象一样是header +字段。在我的PC / JVM上,
header - 8 bytesint length - 4 byteslong 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, 0, 0, 0, 0, 0, 0, 0, 0][8, 15, -114, 24, 0, 0, 0, 0, 0, 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, 12, mem); unsafe.putInt(a1, 8, 1000000); } System.out.println(System.currentTimeMillis() - t0);
需要10毫秒。
5)C ++中有malloc和alloc,malloc只是分配内存块,calloc也会将其初始化为零。
cpp
...JNIEXPORT void JNICALL Java_Test_malloc(JNIEnv *env, jobject obj, jint n) { malloc(n);}
爪哇
private native static void malloc(int n);for (int i = 0; i < 500; i++) { malloc(1000000);}
结果malloc-78毫秒;Calloc-468毫秒
结论
- 似乎由于无用的元素归零,Java数组的创建很慢。
- 我们无法更改它,但是Oracle可以更改。无需更改JLS中的任何内容,只需将本地方法添加到java.lang.reflect.Array之类的
公共静态本机xxx [] newUninitialziedXxxArray(int size);
适用于所有原始数字类型(字节-双精度)和char类型。它可以在整个JDK中使用,就像在java.util.Arrays中一样
public static int[] copyOf(int[] original, int newLength) { int[] copy = Array.newUninitializedIntArray(newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); ...
或java.lang.String
public String concat(String str) { ...char[] buf = Array.newUninitializedCharArray(count + otherLen); getChars(0, count, buf, 0); ...
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)