java - interfaz - ¿Por qué existe sun.misc.Unsafe y cómo puede usarse en el mundo real?
swing containers netbeans (16)
Clase Unsafe
Una colección de métodos para realizar operaciones inseguras de bajo nivel. Aunque la clase y todos los métodos son públicos, el uso de esta clase es limitado porque solo el código de confianza puede obtener instancias de la misma.
Un uso de esto está en las clases java.util.concurrent.atomic
:
Me encontré con el paquete sun.misc.Unsafe el otro día y me sorprendió lo que podía hacer.
Por supuesto, la clase es indocumentada, pero me preguntaba si alguna vez hubo una buena razón para usarla. ¿Qué escenarios podrían surgir donde necesitarías usarlo? ¿Cómo podría usarse en un escenario del mundo real?
Además, si lo necesita, ¿eso no indica que probablemente haya algún problema con su diseño?
¿Por qué Java incluye esta clase?
Úselo para acceder y asignar grandes cantidades de memoria de manera eficiente, como en su propio motor de voxel. (Es decir, juego de estilo Minecraft.)
En mi experiencia, la JVM a menudo no puede eliminar el control de límites en el lugar en el que realmente lo necesita. Por ejemplo, si está iterando sobre una matriz grande, pero el acceso a la memoria real está escondido debajo de una llamada de método no virtual * en el bucle, la JVM aún puede realizar una verificación de límites con cada acceso a la matriz, en lugar de una vez antes el lazo. Por lo tanto, para obtener ganancias de rendimiento potencialmente grandes, puede eliminar la verificación de límites de JVM dentro del bucle a través de un método que emplea sun.misc.Unsafe para acceder a la memoria directamente, asegurándose de realizar cualquier verificación de límites en los lugares correctos. (Vas a ver los límites en algún nivel, ¿verdad?)
* por no virtual, quiero decir que la JVM no debería tener que resolver dinámicamente cualquiera que sea su método particular, porque ha garantizado correctamente que la clase / método / instancia es una combinación de static / final / what-have-you.
Para mi motor voxel de cosecha propia, esto resultó en una ganancia de rendimiento dramática durante la generación de trozos y la serialización (en lugares donde estaba leyendo / escribiendo en toda la matriz a la vez). Los resultados pueden variar, pero si su problema es la falta de eliminación de límites, esto lo solucionará.
Hay algunos problemas potencialmente importantes con esto: específicamente, cuando proporciona la capacidad de acceder a la memoria sin verificación de límites a los clientes de su interfaz, probablemente los abusarán. (No olvide que los hackers también pueden ser clientes de su interfaz ... especialmente en el caso de un motor voxel escrito en Java). Por lo tanto, debe diseñar su interfaz de manera tal que no se pueda abusar del acceso a la memoria, o debe ser extremadamente cuidadoso para validar los datos de usuario antes de que se mezclen con su interfaz peligrosa. Teniendo en cuenta las cosas catastróficas que un pirata informático puede hacer con el acceso sin control a la memoria, probablemente sea mejor adoptar ambos enfoques.
Basado en un análisis muy breve de la biblioteca Java 1.6.12 que usa eclipse para el seguimiento de referencias, parece que cada funcionalidad útil de Unsafe
está expuesta de maneras útiles.
Las operaciones CAS se exponen a través de las clases Atómicas *. Las funciones de manipulación de la memoria están expuestas a través de DirectByteBuffer Sync (estacionar, desempaquetar) están expuestas a través del AbstractQueuedSynchronizer, que a su vez es utilizado por las implementaciones de bloqueo.
Con solo ejecutar una search en un motor de búsqueda de código, obtengo los siguientes ejemplos:
- Java Object Notation : utilícelo para un procesamiento de matriz más eficiente, citando el javadoc
Clase simple para obtener acceso al objeto {@link Unsafe}. {@link Unsafe} * es necesario para permitir operaciones CAS eficientes en arrays. Tenga en cuenta que las versiones en {@link java.util.concurrent.atomic}, como {@link java.util.concurrent.atomic.AtomicLongArray}, requieren garantías adicionales de pedido de memoria que generalmente no son necesarias en estos algoritmos y también son caras en la mayoría de los procesadores.
- SoyLatte - java 6 para el extracto de osx javadoc
/ ** Clase base para campos de campo basados en sun.misc.Unsafe basados en campos estáticos. La observación es que solo hay nueve tipos de campos desde el punto de vista del código de reflexión: los ocho tipos primitivos y Objeto. El uso de la clase Inseguro en lugar de los códigos de byte generados ahorra memoria y tiempo de carga para los FieldAccessors generados dinámicamente. * /
- SpikeSource
/ * FinalFields que se envían a través del cable. ¿Cómo desmarcar y recrear el objeto en el lado receptor? No queremos invocar al constructor, ya que establecería valores para los campos finales. Tenemos que recrear el campo final exactamente como estaba en el lado del remitente. El sun.misc.Unsafe hace esto por nosotros. * /
Hay muchos otros ejemplos, solo siga el enlace de arriba ...
El objeto parece ser la disponibilidad para trabajar en un nivel inferior al que generalmente permite el código Java. Si está codificando una aplicación de alto nivel, la JVM abstrae el manejo de la memoria y otras operaciones fuera del nivel de código, por lo que es más fácil de programar. Al utilizar la biblioteca no segura, está completando efectivamente las operaciones de bajo nivel que normalmente se realizan por usted.
Como woliveirajr dijo, "random ()" usa el programa No seguro para sembrar, así como muchas otras operaciones usarán la función allocateMemory () incluida en No seguro.
Como programador, es probable que pueda salirse con la suya sin tener que usar esta biblioteca, pero tener un control estricto sobre los elementos de bajo nivel puede ser útil (por eso aún existe el ensamblado y (en menor medida) el código C en los principales productos)
Hemos implementado enormes colecciones como Arrays, HashMaps, TreeMaps usando Unsafe.
Y para evitar / minimizar la fragmentación, implementamos el asignador de memoria utilizando los conceptos de dlmalloc sobre inseguro.
Esto nos ayudó a obtener el rendimiento en concurrencia.
Interesante, nunca había oído hablar de esta clase (lo que probablemente sea algo bueno, de verdad).
Una cosa que me viene a la mente es usar Unsafe#setMemory para Unsafe#setMemory a cero los buffers que contenían información confidencial en un punto (contraseñas, claves, ...). Incluso se podría hacer esto en campos de objetos "inmutables" (entonces, supongo, una vez más, un simple reflejo podría hacer el truco aquí también). No soy un experto en seguridad, así que toma esto con un grano de sal.
Las colecciones fuera de la pila pueden ser útiles para asignar grandes cantidades de memoria y desasignarla inmediatamente después de su uso sin interferencia del GC. Escribí una library para trabajar con matrices / listas fuera de pila basadas en sun.misc.Unsafe
.
Lo necesita si necesita reemplazar la funcionalidad proporcionada por una de las clases que la usa actualmente.
Puede ser una serialización / deserialización personalizada / más rápida / más compacta, una versión más rápida / más grande de búfer / tamaño variable de ByteBuffer, o agregar una variable atómica, por ejemplo, una no compatible actualmente.
Lo he usado para todos estos en algún momento.
No lo he usado yo mismo, pero supongo que si tiene una variable que solo se lee ocasionalmente por más de un hilo (por lo que realmente no quiere que sea volátil), podría usar el putObjectVolatile
al escribirlo en el hilo principal. y readObjectVolatile
al hacer lecturas raras de otros subprocesos.
Para una copia de memoria eficiente (más rápida de copiar que System.arraycopy () para bloques cortos al menos); tal como lo usan los codecs Java LZF y Snappy . Utilizan ''getLong'' y ''putLong'', que son más rápidos que hacer copias byte por byte; Especialmente eficiente al copiar elementos como bloques de 16/32/64 bytes.
Recientemente estuve trabajando en la reimplementación de la JVM y descubrí que un número sorprendente de clases se implementan en términos de Unsafe
. La clase está diseñada principalmente para los implementadores de bibliotecas de Java y contiene características que son fundamentalmente inseguras pero necesarias para crear primitivos rápidos. Por ejemplo, existen métodos para obtener y escribir desplazamientos de campo sin procesar, usar sincronización a nivel de hardware, asignar y liberar memoria, etc. No está diseñado para que lo utilicen los programadores de Java normales; es indocumentado, específico de la implementación e intrínsecamente inseguro (de ahí el nombre). Además, creo que el SecurityManager
no permitirá el acceso a él en casi todos los casos.
En resumen, existe principalmente para permitir que los implementadores de bibliotecas accedan a la máquina subyacente sin tener que declarar cada método en ciertas clases como AtomicInteger
nativo. No debería necesitar usarlo ni preocuparse por ello en la programación de rutina de Java, ya que el objetivo principal es hacer que el resto de las bibliotecas sean lo suficientemente rápidos para que no necesite ese tipo de acceso.
Un ejemplo de su uso es el método aleatorio, que llama a los inseguros a cambiar la semilla .
http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html .
ejemplos
VM "intrinsification". es decir, CAS (Compare-and-Swap) utilizado en tablas de hash sin bloqueo, por ejemplo: sun.misc.Unsafe.compareAndSwapInt puede realizar llamadas JNI reales en código nativo que contiene instrucciones especiales para CAS
Lea más sobre CAS aquí http://en.wikipedia.org/wiki/Compare-and-swap
La funcionalidad sun.misc.Unsafe de la máquina virtual host se puede utilizar para asignar objetos sin inicializar y luego interpretar la invocación del constructor como cualquier otra llamada de método.
Uno puede rastrear los datos desde la dirección nativa. ¡Es posible recuperar la dirección de memoria de un objeto usando la clase java.lang.Unsafe, y operar en sus campos directamente a través de métodos de obtención / colocación no seguros!
Compilación de optimizaciones de tiempo para JVM. VM de alto rendimiento usando "magia", que requiere operaciones de bajo nivel. por ejemplo: http://en.wikipedia.org/wiki/Jikes_RVM
Asignación de memoria, sun.misc.Unsafe.allocateMemory, por ejemplo: - DirectByteBuffer constructor lo llama internamente cuando se invoca ByteBuffer.allocateDirect
Rastreo de la pila de llamadas y reproducción con valores instanciados por sun.misc.Unsafe, útil para instrumentación
sun.misc.Unsafe.arrayBaseOffset y arrayIndexScale se pueden usar para desarrollar arraylets, una técnica para dividir eficientemente arrays grandes en objetos más pequeños para limitar el costo en tiempo real de escanear, actualizar o mover operaciones en objetos grandes
http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java
más sobre referencias aquí: http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html
Unsafe.park()
y Unsafe.unpark()
para la construcción de estructuras de control de concurrencia personalizadas y mecanismos de planificación cooperativa.
Unsafe.throwException : permite lanzar una excepción marcada sin declararla.
Esto es útil en algunos casos en los que se trata con la reflexión o AOP.
Supongamos que crea un proxy genérico para una interfaz definida por el usuario. Y el usuario puede especificar qué excepción produce la implementación en un caso especial simplemente declarando la excepción en la interfaz. Entonces, esta es la única manera que conozco, de elevar una excepción marcada en la Implementación dinámica de la Interfaz.
import org.junit.Test;
/** need to allow forbidden references! */ import sun.misc.Unsafe;
/**
* Demonstrate how to throw an undeclared checked exception.
* This is a hack, because it uses the forbidden Class {@link sun.misc.Unsafe}.
*/
public class ExceptionTest {
/**
* A checked exception.
*/
public static class MyException extends Exception {
private static final long serialVersionUID = 5960664994726581924L;
}
/**
* Throw the Exception.
*/
@SuppressWarnings("restriction")
public static void throwUndeclared() {
getUnsafe().throwException(new MyException());
}
/**
* Return an instance of {@link sun.misc.Unsafe}.
* @return THE instance
*/
@SuppressWarnings("restriction")
private static Unsafe getUnsafe() {
try {
Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
singleoneInstanceField.setAccessible(true);
return (Unsafe) singleoneInstanceField.get(null);
} catch (IllegalArgumentException e) {
throw createExceptionForObtainingUnsafe(e);
} catch (SecurityException e) {
throw createExceptionForObtainingUnsafe(e);
} catch (NoSuchFieldException e) {
throw createExceptionForObtainingUnsafe(e);
} catch (IllegalAccessException e) {
throw createExceptionForObtainingUnsafe(e);
}
}
private static RuntimeException createExceptionForObtainingUnsafe(final Throwable cause) {
return new RuntimeException("error while obtaining sun.misc.Unsafe", cause);
}
/**
* scenario: test that an CheckedException {@link MyException} can be thrown
* from an method that not declare it.
*/
@Test(expected = MyException.class)
public void testUnsingUnsaveToThrowCheckedException() {
throwUndeclared();
}
}