- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
正如我们所知,Java 总是在创建数组时对其进行初始化。 IE。 new int[1000000]
总是返回一个所有元素都为 0 的数组。我知道这对于对象数组来说是必须的,但对于原始数组( 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] 的时间小于 1 毫秒,字节 [1000000] 的时间约为 500 毫秒。听起来让我印象深刻。
2) 我们在 JDK 中没有用于填充数组的快速( native )方法,Arrays.fill 太慢了,所以让我们至少看看使用 native System.arraycopy 复制 1,000,000 个大小的数组需要多少 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.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 毫秒,对于新字节 [1000000] 花费了 500 毫秒。
4) Unsafe 没有直接的方法来处理数组。它需要知道类字段,但反射显示数组中没有字段。关于数组内部的信息不多,我猜它是特定于 JVM/平台的。然而,与任何其他 Java 对象一样,它是 header + 字段。在我的 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, 0, 0, 0, 0, 0, 0, 0, 0]
[8, 15, -114, 24, 0, 0, 0, 0, 0, 0]
你可以看到数组的数据没有被初始化。
现在我将更改我们的数组长度(尽管它仍然指向 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);
}
java
private native static void malloc(int n);
for (int i = 0; i < 500; i++) {
malloc(1000000);
}
结果 malloc - 78 毫秒; calloc - 468 毫秒
结论
我们无法更改它,但 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, 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);
...
关于java - 有没有办法在不初始化的情况下创建原始数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13780350/
我是 Java 新手,这是我的代码, if( a.name == b.name && a.displayname == b.displayname && a.linknam
在下面的场景中,我有一个 bool 值。根据结果,我调用完全相同的函数,唯一的区别是参数的数量。 var myBoolean = ... if (myBoolean) { retrieve
我是一名研究 C++ 的 C 开发人员: 我是否正确理解如果我抛出异常然后堆栈将展开直到找到第一个异常处理程序?是否可以在不展开的情况下在任何 throw 上打开调试器(即不离开声明它的范围或任何更高
在修复庞大代码库中的错误时,我观察到一个奇怪的情况,其中引用的动态类型从原始 Derived 类型更改为 Base 类型!我提供了最少的代码来解释问题: struct Base { // some
我正在尝试用 C# 扩展给定的代码,但由于缺乏编程经验,我有点陷入困境。 使用 Visual Studio 社区,我尝试通过控制台读出 CPU 核心温度。该代码使用开关/外壳来查找传感器的特定名称(即
这可能是一个哲学问题。 假设您正在向页面发出 AJAX 请求(这是使用 Prototype): new Ajax.Request('target.asp', { method:"post", pa
我有以下 HTML 代码,我无法在所有浏览器中正常工作: 我试图在移动到
我对 Swift 很陌生。我如何从 addPin 函数中检索注释并能够在我的 addLocation 操作 (buttonPressed) 中使用它。我正在尝试使用压力触摸在 map 上添加图钉,在两
我设置了一个详细 View ,我是否有几个 Nib 文件根据在 Root View Controller 的表中选择的项目来加载。 我发现,对于 Nibs 的类,永远不会调用 viewDidUnloa
我需要动态访问 json 文件并使用以下代码。在本例中,“bpicsel”和“temp”是变量。最终结果类似于“data[0].extit1” var title="data["+bpicsel+"]
我需要使用第三方 WCF 服务。我已经在我的证书存储中配置了所需的证书,但是在调用 WCF 服务时出现以下异常。 向 https://XXXX.com/AHSharedServices/Custome
在几个 SO 答案(1、2)中,建议如果存在冲突则不应触发 INSERT 触发器,ON CONFLICT DO NOTHING 在触发语句中。也许我理解错了,但在我的实验中似乎并非如此。 这是我的 S
如果进行修改,则会给出org.hibernate.NonUniqueObjectException。在我的 BidderBO 类(class)中 @Override @Transactional(pr
我使用 indexOf() 方法来精细地查找数组中的对象。 直到此刻我查了一些资料,发现代码应该无法正常工作。 我在reducer中尝试了上面的代码,它成功了 let tmp = state.find
假设我有以下表格: CREATE TABLE Game ( GameID INT UNSIGNED NOT NULL, GameType TINYINT UNSIGNED NOT NU
代码: Alamofire.request(URL(string: imageUrl)!).downloadProgress(closure: { (progress) in
我是一名优秀的程序员,十分优秀!