6

この質問(「なぜ java.lang.Object は抽象的ではないのですか?」)について以前にコメントしましたbyte[0]が、 をロックとして使用する方がjava.lang.Object. これをどこかで読んだことはあると思いますが、どこだったか思い出せません。これが本当かどうか知っている人はいますか?

長さフィールドを格納するために追加のストレージが必要であることが指摘されていたため、これは利点を無効にする可能性があると指摘されていましたが、byte[0]よりもわずかに少ないバイトコードを必要とするインスタンス化が原因であると思われます。Objectbyte[0]

4

6 に答える 6

15

java.lang.instrument.Instrumentation を使用してサイズを確認します。
オブジェクトは 8 バイトを使用し、byte[0] は 16 バイトを必要とします。(サイズがバイト単位であるかどうかは不明で、文書化されていません)。

オブジェクトと byte[0] を作成する時間もありました (2 回): オブジェクトが勝者です。

(すべてのテストは、DELL ラップトップ、Intel 2GHz、Windos XP で実行されます)

clientVMの使用

java version "1.6.0_16"
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) Client VM (build 14.2-b01, mixed mode)

an implementation-specific approximation of the amount of storage
Object  = 8
byte[0] = 16

time to create 1000000000 instances
Object:  elapsed=11,140   cpu=9,766    user=9,703    [seconds]
byte[0]: elapsed=18,248   cpu=15,672   user=15,594   [seconds]

time to create 1000000000 instances
Object:  elapsed=11,135   cpu=9,828    user=9,750    [seconds]
byte[0]: elapsed=18,271   cpu=15,547   user=15,469   [seconds]

serverVMの使用

java version "1.6.0_16"
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) Server VM (build 14.2-b01, mixed mode)

an implementation-specific approximation of the amount of storage
Object  = 8
byte[0] = 16

time to create 1000000000 instances
Object:  elapsed=8,441    cpu=7,156    user=7,125    [seconds]
byte[0]: elapsed=11,237   cpu=8,609    user=8,500    [seconds]

time to create 1000000000 instances
Object:  elapsed=8,501    cpu=7,234    user=7,156    [seconds]
byte[0]: elapsed=11,023   cpu=8,688    user=8,641    [seconds]

読みやすさのためだけでなく、私はとどまりますnew Object():-)

コード

public class ObjectArrayCompare {

  private static Object o;

  public static void main(String[] args) {
    Instrumentation instr = InstrumentationAgent.getInstrumentation();
    if (instr == null) {
        System.err.println("No Instrumentation, use \"-javaagent:Instrumentation.jar\"");
        return;
    }
    System.out.println();
    System.out.println("an implementation-specific approximation of the amount of storage");
    System.out.println("Object  = " + instr.getObjectSize(new Object()));
    System.out.println("byte[0] = " + instr.getObjectSize(new byte[0]));
    System.out.println();

    final int MAX = (int) 1.0e9;
    Timer timer;
    Times times;

    for (int j = 0; j < 2; j++) {
      System.out.println("time to create " + MAX + " instances"); 
      timer = new Timer();
      for (int i = 0; i < MAX; i++) {
        o = new Object();
      }
      times = timer.times();
      System.out.println("Object:  " + times);

      timer = new Timer();
      for (int i = 0; i < MAX; i++) {
        o = new byte[0];
      }
      times = timer.times();
      System.out.println("byte[0]: " + times);

      System.out.println();
    }
  }
}

Timer *を使用ThreadMXBeanして時間を取得します。

* Timer は、タイミングを計るために作成したクラスであり、Java Timer のものではありません。

于 2010-01-23T21:31:19.830 に答える
13

私はそれをテストするのに十分興味がありました。ソースコード:

public class Test {
    public static Object returnObject() {
        return new Object();
    }

    public static byte[] returnArray(){
        return new byte[0];
    }
}

バイトコード:

public static java.lang.Object returnObject();
  Code:
   0:   new     #2; //class java/lang/Object
   3:   dup
   4:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   7:   areturn

public static byte[] returnArray();
  Code:
   0:   iconst_0
   1:   newarray byte
   3:   areturn

配列の作成には独自の JVM オペコードがあるため、配列のバイトコードは短くなります。しかし、それはどういう意味ですか?本当に何もありません。これは仮想マシンであるため、バイトコード命令が少ないほど、実際の物理 CPU の作業が少なくなるという保証はまったくありません。もちろん、プロファイリングを開始することもできますが、それはまったく無意味です。違いがあったとしても、どちらにせよ、それは決して問題にはなりません。現在、オブジェクトの作成は信じられないほど高速です。long合計時間を測定する前に、おそらくループ インデックスの使用を開始する必要があります。

于 2010-01-22T21:13:23.227 に答える
5

Java Language Specによると 、「すべてのクラスおよび配列型はクラス Object のメソッドを継承する」ため、byte[0] をより効率的に管理する方法がわかりません。

これは、仕様の初版にも当てはまるようです。「配列型のスーパークラスはオブジェクトと見なされます」。

于 2010-01-22T21:09:27.713 に答える
3

配列を使用すると、読者の私見を混乱させる可能性が高くなります。

作成するオブジェクトを少なくすることは、多く作成することよりも効率的です。

于 2010-01-23T19:13:06.823 に答える
1

あなたの質問は「効率」に言及していますが、どのような効率を求めているかは述べていません。これまでの答えはオブジェクトのサイズに関するものですが、逆参照とどちらの表現でも固有のロックを使用するための実行時のコストは同じである必要があります。

また、組み込みロックを使用するオーバーヘッドを、java.util.concurrent.locks.ReentrantLock明示的に使用するか、自分で作成したものと比較することもできますAbstractQueuedSynchronizer。個別に割り当てられたオブジェクトへの追加の参照を許容できるかどうかを評価するには、問題の詳細が必要ですがbyte、配列を既に検討していることを考えると、参照とは別の組み込みロックの使用を検討する必要がありますthis

于 2010-01-23T23:46:09.310 に答える