Pregunta

os comentaba anteriormente en esta pregunta ( "¿Por qué Java. lang.Object no es abstracto? ") indicando que había oído que el uso de un byte[0] como un bloqueo fue ligeramente más eficaz que utilizar un java.lang.Object. Estoy seguro de que he leído esto en alguna parte, pero no puedo recordar dónde:? ¿Alguien sabe si esto es realmente cierto

sospecho que es debido a la creación de instancias de byte[0] que requiere un poco menos que el código de bytes Object, aunque se señaló que byte[0] requiere almacenamiento adicional con el fin de almacenar el campo de longitud y por lo que suena como esto podría negar cualquier beneficio.

¿Fue útil?

Solución

Tengo curiosidad suficiente para probarlo. Código fuente:

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

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

código de bytes:

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

Así que tienes razón en que el código de bytes es más corto para las matrices, debido creación de la matriz tiene su propio código de operación JVM. Pero ¿qué significa eso? Nada en realidad. Es una máquina virtual, por lo que no hay absolutamente ninguna garantía de que un menor número de instrucciones de código de bytes significan menos trabajo para la CPU física real. Podríamos comenzar a perfilar, por supuesto, pero eso sería bastante inútil. Si hay una diferencia en absoluto, no importa la forma, lo hará nunca la materia. la creación de objetos es increíblemente rápido hoy en día. Probablemente tendría que empezar a utilizar long para su índice del bucle antes de que pueda medir el tiempo total.

Otros consejos

El uso de java.lang.instrument.Instrumentation para comprobar los tamaños:
Objeto utiliza 8 bytes, el byte [0] necesita 16 bytes. (No estoy seguro si el tamaño es en bytes, no documentado).

También tiene el tiempo para crear un objeto y un byte [0] (2 veces): El objeto es el ganador.

(todas las pruebas se ejecutan en un ordenador portátil de Dell, Intel a 2 GHz, Windos XP)

Uso de la 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 de la 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]

I permanecerá con new Object(), no sólo debido a la legibilidad :-)

El Código

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();
    }
  }
}

Temporizador * usos ThreadMXBean para obtener los tiempos.

* Temporizador es una clase que hice para timming, es no uno de los Temporizador de Java.

es más probable que confundir al lector mi humilde opinión Usando una matriz.

Creación de objetos menos es más eficiente que la creación de más, por lo que si es que alguna vez lo hizo crear suficientes objetos que no importaba, que está creando demasiados.

El patrón de uso de una matriz vacía en Java como un objeto de bloqueo tiene poco que ver con el rendimiento.

arrays vacíos (incluso new Object[0]) son preferibles porque son serializable. Mediante el uso de new Object() estás dando serialización automática.

I se acostumbró a hacer (no preocuparse por el rendimiento):

private final Object lock = new Object[0];

matrices primitivas toman menos de código de bytes para crear, así que tal vez new byte[0] sería "mejor".

Ver: ¿Está bien para hacer el transitorio de bloqueo para una clase Serializable

?

Su pregunta menciona la "eficiencia", pero no dice qué tipo de eficiencia que está buscando. Las respuestas hasta el momento se refieren a la Tamaño de los objetos, pero los costos de tiempo de ejecución de eliminación de referencias y con el bloqueo intrínseco, ya sea en la representación debe ser el mismo.

También se puede comparar la sobrecarga de uso de bloqueos intrínsecas a la utilización de java.util.concurrent.locks.ReentrantLock explícita o uno que escribe a sí mismo en lo alto AbstractQueuedSynchronizer . Si se puede tolerar una referencia adicional a un objeto asignado por separado, requiere más detalles sobre su problema de evaluar, pero teniendo en cuenta que ya está pensando en matrices byte, debe estar considerando el uso de un bloqueo intrínseco distinto de su referencia this.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top