Frage

, kommentierte ich früher auf diese Frage ( "Warum Java. lang.Object ist nicht abstrakt? ") besagt, dass ich habe gehört, dass ein byte[0] als Schloss war etwas effizienter als ein java.lang.Object verwenden. Ich bin sicher, habe ich das irgendwo gelesen, aber ich kann mich nicht erinnern, wo: Wer weiß, ob dies tatsächlich wahr

Ich vermute, es ist wegen der Instanziierung byte[0] erfordert etwas weniger Byte-Code als Object, obwohl darauf hingewiesen wurde, dass byte[0] erfordert zusätzlichen Speicherplatz, um das Längenfeld zu speichern, und so ist es klingt wie könnte dies keinen Nutzen zunichte machen.

War es hilfreich?

Lösung

Ich habe neugierig genug, um es zu testen. Sourcecode:

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

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

Bytecode:

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

Sie sind also richtig, dass der Byte-Code ist kürzer für Arrays, da Array-Erstellung eine eigene JVM Opcode hat. Aber was bedeutet das? Nichts wirklich. Es ist eine virtuelle Maschine, so gibt es absolut keine Garantie, dass weniger Bytecodebefehle weniger Arbeit für die tatsächliche physische CPU bedeuten. Wir konnten Profilierungs natürlich beginnen, aber das wäre ziemlich sinnlos. Wenn es einen Unterschied überhaupt ist, nicht die Art und Weise wichtig, wird es nie Angelegenheit. Objekterstellung ist unglaublich schnell heute. Sie würden vermutlich mit long für Ihren Schleifenindex starten, bevor Sie sogar die Gesamtzeit messen kann.

Andere Tipps

Mit java.lang.instrument.Instrumentation die Größen zu überprüfen:
Objekt verwendet 8 Bytes, Byte [0] benötigt 16 Byte. (Nicht sicher, ob die Größe in Bytes, nicht dokumentiert).

Ich habe auch die Zeit, um ein Objekt und ein Byte [0] (2-mal) zu erstellen: Object ist der Gewinner.

(alle Tests laufen auf einem DELL Laptop, Intel 2 GHz, Windos XP)

Mit dem client VM

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]

Mit dem server VM

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]

Ich werde mit new Object() bleiben, nicht nur wegen der Lesbarkeit :-)

Der Kodex

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 * Anwendungen ThreadMXBean die Zeiten zu erhalten.

* Timer ist eine Klasse I für timming gemacht, es ist nicht eine der Java-Timer ist.

Nach dem Java Language Spec „alle Klasse und Array Typen erben die Methoden der Klasse Object“, so dass ich weiß nicht, wie Byte [0] gelänge, effizienter zu sein.

Das scheint für die um wahr zu sein zuerst Ausgabe der spec auch: „die übergeordnete Klasse eines Array-Typ wird als Objekt sein“

ein Array ist wahrscheinlicher, den Leser IMHO zu verwirren.

weniger Objekte zu schaffen, ist effizienter als die Schaffung von mehr, also wenn es jemals genug Objekten erstellt hat, die es darauf ankam, zu viele schaffen.

Das Muster eines leeres Array der Verwendung in Java als Sperrobjekt hat wenig mit Leistung zu tun.

Leere Arrays (auch new Object[0]) bevorzugt, da sie serialisierbar sind. Durch die Verwendung von new Object() Sie Aufgeben automatische Serialisierung.

habe ich verwendet, um zu tun (nie Sorge um Leistung):

private final Object lock = new Object[0];

Primitive Arrays nimmt weniger Bytecode, zu schaffen, so wäre vielleicht new byte[0] "besser" sein.

Siehe auch: Ist es in Ordnung, das Schloss transienten für eine Serializable Klasse zu machen

?

Ihre Frage erwähnt „Effizienz“, aber nicht sagen, welche Art von Effizienz sind nach. Die Antworten bisher betreffen die Größe der Objekte, aber die Laufzeitkosten von dereferencing und mit der inneren Sperre in jeder Darstellung soll das gleiche sein.

Sie können vergleichen auch den Aufwand der Verwendung von Eigenschlösser mit java.util.concurrent.locks.ReentrantLock explizit oder eine Sie sich oben auf AbstractQueuedSynchronizer . Ob Sie können einen zusätzlichen Verweis auf eine separat zugewiesene Objekt tolerieren erfordert weitere Einzelheiten über Ihr Problem zu beurteilen, aber wenn man bedenkt, dass Sie in Betracht ziehen bereits byte Arrays, müssen Sie in Erwägung ziehen mit einem inneren Sperre unterscheidet sich von Ihrem this Referenz.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top