Object vs byte [0] come blocco
-
22-09-2019 - |
Domanda
ho commentato in precedenza su questa domanda ( "Perché Java. lang.Object non è astratta? ") affermando che avevo sentito che l'utilizzo di un byte[0]
come una serratura era leggermente più efficiente di utilizzare un java.lang.Object
. Sono sicuro che ho letto da qualche parte, ma non riesco a ricordare dove: Qualcuno sa se questo è effettivamente vero
Ho il sospetto che sia a causa della creazione di un'istanza di byte[0]
che richiede un po 'meno byte code di Object
, anche se è stato sottolineato che byte[0]
richiede memoria aggiuntiva per memorizzare la lunghezza campo e così suona come questo potrebbe negare alcun beneficio.
Soluzione
ho avuto abbastanza curiosi di provarlo. Codice sorgente:
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
Quindi hai ragione in quanto il bytecode è più breve per le matrici, perché la creazione array ha un proprio codice operativo JVM. Ma che cosa significa? Niente. Si tratta di una macchina virtuale, quindi non c'è assolutamente alcuna garanzia che un minor numero di istruzioni bytecode significa meno lavoro per la CPU fisico reale. Potremmo iniziare il profiling, naturalmente, ma che sarebbe del tutto inutile. Se c'è una differenza a tutti, non importa in che modo, non sarà mai mai importa. la creazione di oggetti è incredibilmente veloce al giorno d'oggi. probabilmente dovreste iniziare a utilizzare long
per il vostro indice del ciclo prima di poter anche misurare il tempo totale.
Altri suggerimenti
Utilizzando java.lang.instrument.Instrumentation per controllare le dimensioni:
Oggetto utilizza 8 byte, byte [0] bisogno di 16 byte. (Non so se la dimensione è in byte, non documentato).
Ho anche avuto il tempo per creare un oggetto e un byte [0] (2 volte): Object è il vincitore.
(tutti i test eseguiti su un computer portatile Dell, Intel 2GHz, Windos XP)
Uso della 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]
Uso della 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]
io resterò con new Object()
, non solo per la leggibilità :-)
il codice
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 * utilizza ThreadMXBean
per ottenere i tempi.
* Timer è una classe che ho fatto per timming, è non una delle Java Timer del.
Secondo il linguaggio Java Spec , "tutte le classi e la matrice tipi ereditano i metodi della classe Object", quindi non so come byte [0] riusciva a essere più efficiente.
Questa sembra essere vero per il rel="noreferrer"> pure: "la superclasse di un tipo di matrice è considerato oggetto"
L'utilizzo di un array è più probabile che confondere l'IMHO lettore.
La creazione di oggetti meno è più efficiente rispetto alla creazione di più, quindi se mai fatto creare abbastanza oggetti che importasse, si sta creando troppi.
Il pattern di utilizzare un array vuoto in Java come un oggetto di blocco ha poco a che fare con le prestazioni.
array vuoti (anche new Object[0]
) sono preferibili perché sono serializzabile. Utilizzando new Object()
stai rinunciando serializzazione automatica.
mi sono abituato a fare (mai preoccuparsi di performance):
private final Object lock = new Object[0];
array primitivi prendono meno bytecode per creare, quindi forse new byte[0]
sarebbe "migliore".
Vedere: Va bene per rendere il transitorio di blocco per una classe Serializable
La tua domanda parla di "efficienza", ma non dice che tipo di rendimento che stai cercando. Le risposte finora riguardano il size degli oggetti, ma i costi di run-time di dereferencing e utilizzando il blocco intrinseco sia in rappresentanza dovrebbe essere lo stesso.
È inoltre possibile confrontare l'overhead di usare serrature intrinseche di utilizzare java.util.concurrent.locks.ReentrantLock
esplicitamente o quello che scrivere da soli in cima a AbstractQueuedSynchronizer
. Sia che si può tollerare un ulteriore riferimento a un oggetto separatamente allocato richiede più dettagli sul problema di valutare, ma dato che si sta già prendendo in considerazione gli array byte
, è necessario considerando usando un blocco intrinseco distinto dal vostro riferimento this
.