studio programacion móviles libros libro desarrollo desarrollar curso aprende aplicaciones java memory jvm unsafe

java - móviles - manual de programacion android pdf



¿Hay alguna forma de obtener una dirección de referencia? (5)

En realidad, la dirección se puede obtener con sun.misc.Unsafe pero es realmente muy inseguro. GC a menudo mueve objetos.

Esta pregunta ya tiene una respuesta aquí:

En Java, ¿hay alguna forma de obtener una dirección de referencia?

String s = "hello"

¿Puedo obtener la dirección de s, también, puedo obtener la dirección del objeto al que se refiere la referencia?


No es posible en Java obtener una dirección de referencia de un objeto, como su cadena. La dirección de referencia de un objeto está oculta para el usuario, en Java.

En C, puede hacerlo a través del concepto de punteros. Java tiene un concepto similar, a bajo nivel, y esta es la dirección de referencia. La referencia es como un puntero C, pero no es explícito. En C, puede hacer la operación de referenciar punteros, a través de * , pero en Java, no es posible.

No me gusta mucho el lenguaje C, también porque los indicadores, según yo, no son un concepto fácil de manejar. Esta es una de las razones por las que me gusta Java, porque el programador no necesita preocuparse por el puntero de un objeto.

Como dice @jarnbjo, puedes verificar, si algunas referencias son similares, con una sintaxis como esta:

String s = "hello"; String g = s; System.out.println("Are the reference addresses similar? "+(s==g)); g = "goodbye"; System.out.println("Are the reference addresses similar? "+(s==g));

Tenga en cuenta que == verifica la igualdad de la dirección de referencia. Si desea verificar la igualdad del valor de las cadenas, use el método equals() .

Le sugiero que lea this pregunta SO, this página de Wikipedia y this página.


No, no puedes. Incluso utilizando Java Native Interface (JNI), solo puede obtener un identificador opaco para la estructura de datos, no un puntero al objeto JVM real.

¿Por qué querrías tal cosa? No necesariamente estaría en una forma que pudieras usar para nada, de todos modos, incluso desde código nativo.


Puede obtener el índice del objeto con Inseguro. Dependiendo de cómo la JVM está utilizando la memoria (direcciones de 32 bits, índice de 32 bits, índice de 32 bits con desplazamiento, dirección de 64 bits) puede afectar la utilidad del índice del objeto.

Aquí hay un programa que supone que tiene un índice de 32 bits en una JVM de 64 bits.

import sun.misc.Unsafe; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collections; public class OrderOfObjectsAfterGCMain { static final Unsafe unsafe = getUnsafe(); static final boolean is64bit = true; // auto detect if possible. public static void main(String... args) { Double[] ascending = new Double[16]; for(int i=0;i<ascending.length;i++) ascending[i] = (double) i; Double[] descending = new Double[16]; for(int i=descending.length-1; i>=0; i--) descending[i] = (double) i; Double[] shuffled = new Double[16]; for(int i=0;i<shuffled.length;i++) shuffled[i] = (double) i; Collections.shuffle(Arrays.asList(shuffled)); System.out.println("Before GC"); printAddresses("ascending", ascending); printAddresses("descending", descending); printAddresses("shuffled", shuffled); System.gc(); System.out.println("/nAfter GC"); printAddresses("ascending", ascending); printAddresses("descending", descending); printAddresses("shuffled", shuffled); System.gc(); System.out.println("/nAfter GC 2"); printAddresses("ascending", ascending); printAddresses("descending", descending); printAddresses("shuffled", shuffled); } public static void printAddresses(String label, Object... objects) { System.out.print(label + ": 0x"); long last = 0; int offset = unsafe.arrayBaseOffset(objects.getClass()); int scale = unsafe.arrayIndexScale(objects.getClass()); switch (scale) { case 4: long factor = is64bit ? 8 : 1; final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor; System.out.print(Long.toHexString(i1)); last = i1; for (int i = 1; i < objects.length; i++) { final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor; if (i2 > last) System.out.print(", +" + Long.toHexString(i2 - last)); else System.out.print(", -" + Long.toHexString( last - i2)); last = i2; } break; case 8: throw new AssertionError("Not supported"); } System.out.println(); } private static Unsafe getUnsafe() { try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); return (Unsafe) theUnsafe.get(null); } catch (Exception e) { throw new AssertionError(e); } } }

Ejecutando en la actualización 26 de Java 6 (64 bits con oops comprimidos) y Java 7. Nota: las direcciones y direcciones relativas están en hexadecimal.

Before GC ascending: 0x782322b20, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18 descending: 0x782322e58, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 shuffled: 0x782322ec0, +78, -30, +90, -c0, +18, +90, +a8, -30, -d8, +f0, -30, -90, +60, -48, +60 After GC ascending: 0x686811590, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 descending: 0x686811410, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 shuffled: 0x686811290, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18

O algunas veces

Before GC ascending: 0x782322b20, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18 descending: 0x782322e58, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 shuffled: 0x782323028, -168, +150, -d8, -30, +60, +18, +30, +30, +18, -108, +30, -48, +78, +78, -30 After GC ascending: 0x6868143c8, +4db0, +7120, -bd90, +bda8, -bd90, +4d40, +18, +18, -12710, +18, +80, +18, +ffa8, +220, +6b40 descending: 0x68681d968, +18, +d0, +e0, -165d0, +a8, +fea8, +c110, -5230, -d658, +6bd0, +be10, +1b8, +75e0, -19f68, +19f80 shuffled: 0x686823938, -129d8, +129f0, -17860, +4e88, +19fe8, -1ee58, +18, +18, +bb00, +6a78, -d648, -4e18, +4e40, +133e0, -c770


Sí, puedes hacerlo con inseguro, aunque no sea tan directo. Coloque el objeto o la referencia de instancia en un int [], eso está bien. long [] también debería estar bien.

@Test public void test1() throws Exception { Unsafe unsafe = Util.unsafe; int base = unsafe.arrayBaseOffset(int[].class); int scale = unsafe.arrayIndexScale(int[].class); int shift = 31 - Integer.numberOfLeadingZeros(scale); System.out.printf("base: %s, scale %s, shift: %s/n", base, scale, shift); base = unsafe.arrayBaseOffset(Object[].class); scale = unsafe.arrayIndexScale(Object[].class); shift = 31 - Integer.numberOfLeadingZeros(scale); System.out.printf("base: %s, scale %s, shift: %s/n", base, scale, shift); int[] ints = { 1, 2, 0 }; String string = "abc"; System.out.printf("string: id: %X, hash: %s/n", System.identityHashCode(string), string.hashCode()); unsafe.putObject(ints, offset(2, shift, base), string); System.out.printf("ints: %s, %X/n", Arrays.toString(ints), ints[2]); Object o = unsafe.getObject(ints, offset(2, shift, base)); System.out.printf("ints: %s/n", o); assertSame(string, o); Object[] oa = { 1, 2, string }; o = unsafe.getObject(oa, offset(2, shift, base)); assertSame(string, o); int id = unsafe.getInt(oa, offset(2, shift, base)); System.out.printf("id=%X/n", id); } public static long offset(int index, int shift, int base) { return ((long) index << shift) + base; }