Trasis Inc.

渋谷拠点のシステム開発会社

Javaインスタンス生成性能

概要

大量にオブジェクトを生成しなければならないケースにおいて、オブジェクト生成方法による性能差について調査した。
特に、Java のリフレクションは遅いと聞くが、どのくらい性能がでるのかが気になっていた。

調査に使った Java のバージョン: Sun JDK 1.6.0_05

結論

  • new Foo() の形で生成する方法は、リフレクションを使った他の方法より圧倒的に高速に動作する。
  • リフレクションを使うケースの中では、static な newInstance() をリフレクションで呼ぶ方法が最も高速に動作した。

調査内容

次の3つの生成方法で実行時間を計測した。

  • test-1 – new Foo()
  • test-2 – Class.newInstance()
  • test-3 – Constructor.newInstance()
  • test-4 – Foo の static メソッド newInstance() をリフレクション経由で実行

また test-2 以外のテストケースでは、コンストラクタの引数が無しのケースと int を引数とするケースを調査した。

test-1: new Foo() で生成 (引数なし)

package jp.trasis.test.newInstance;
public class Test1 {
public static void main(String[] args) {
long t = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000 * 30; i++) {
new Test1();
}
System.out.println((System.currentTimeMillis() - t) + " msec");
}
}

test-1-2: new Foo(int)

package jp.trasis.test.newInstance;
public class Test1_2 {
private int v;
public Test1_2(int v) {
this.v = v;
}
public static void main(String[] args) {
long t = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000 * 30; i++) {
new Test1_2(i);
}
System.out.println((System.currentTimeMillis() - t) + " msec");
}
}

test-2: Class.newInstance() で生成

package jp.trasis.test.newInstance;
public class Test2 {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
long t = System.currentTimeMillis();
Class c = Test2.class;
for (int i = 0; i < 1000 * 1000 * 30; i++) {
c.newInstance();
}
System.out.println((System.currentTimeMillis() - t) + " msec");
}
}

test-3: Constructor.newInstance() で生成

package jp.trasis.test.newInstance;
import java.lang.reflect.Constructor;
public class Test3 {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
long t = System.currentTimeMillis();
Class c = Test3.class;
Constructor constructor = c.getConstructor();
for (int i = 0; i < 1000 * 1000 * 30; i++) {
constructor.newInstance();
}
System.out.println((System.currentTimeMillis() - t) + " msec");
}
}

test-3-2: Constructor.newInstance(int) で生成

package jp.trasis.test.newInstance;
import java.lang.reflect.Constructor;
public class Test3_2 {
private int v;
public Test3_2(int v) {
this.v = v;
}
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
long t = System.currentTimeMillis();
Class c = Test3_2.class;
Constructor constructor = c.getConstructor(int.class);
for (int i = 0; i < 1000 * 1000 * 30; i++) {
constructor.newInstance(i);
}
System.out.println((System.currentTimeMillis() - t) + " msec");
}
}

test-4: Foo.newInstance() をリフレクションで実行

package jp.trasis.test.newInstance;
import java.lang.reflect.Method;
public class Test4 {
public static Test4 newInstance() {
return new Test4();
}
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
long t = System.currentTimeMillis();
Class c = Test4.class;
Method method = c.getMethod("newInstance");
for (int i = 0; i < 1000 * 1000 * 30; i++) {
method.invoke(null);
}
System.out.println((System.currentTimeMillis() - t) + " msec");
}
}

test-4-2: Foo.newInstance(int)

package jp.trasis.test.newInstance;
import java.lang.reflect.Method;
public class Test4_2 {
private int v;
private Test4_2(int v) {
this.v = v;
}
public static Test4_2 newInstance(int v) {
return new Test4_2(v);
}
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
long t = System.currentTimeMillis();
Class c = Test4_2.class;
Method method = c.getMethod("newInstance", int.class);
for (int i = 0; i < 1000 * 1000 * 30; i++) {
method.invoke(null, i);
}
System.out.println((System.currentTimeMillis() - t) + " msec");
}
}

実行結果

テストケース 引数なし [msec] 引数あり [msec]
test-1 125 172
test-2 3344
test-3 3281 3891
test-4 1984 2625