Me encontré con el paquete sun.misc. Inseguro el otro día y me sorprendió lo que podía hacer.
Por supuesto, la clase no está documentada, pero me preguntaba si alguna vez había una buena razón para usarla. ¿Qué escenarios podrían surgir en los que tendrías que usarlo? ¿Cómo podría usarse en un escenario del mundo real?
Además, si lo necesita, ¿eso no indica que algo esté mal con su diseño?
¿Por qué Java incluso incluye esta clase?
Respuestas:
ejemplos
VM "intrinsificación". es decir, CAS (Compare-And-Swap) utilizado en tablas de hash sin bloqueo, por ejemplo: sun.misc.Unsafe.compareAndSwapInt puede hacer 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 usar para asignar objetos no inicializados y luego interpretar la invocación del constructor como cualquier otra llamada a método.
Uno puede rastrear los datos de 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 inseguros get / put!
Optimizaciones de tiempo de compilación para JVM. VM de alto rendimiento con "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: - El constructor DirectByteBuffer 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 de manera eficiente matrices grandes en objetos más pequeños para limitar el costo en tiempo real de las operaciones de escaneo, actualización o movimiento 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
fuente
Solo de ejecutar una búsqueda en algún motor de búsqueda de códigos obtengo los siguientes ejemplos:
Hay muchos otros ejemplos, solo siga el enlace de arriba ...
fuente
Interesante, nunca había oído hablar de esta clase (que probablemente sea algo bueno, de verdad).
Una cosa que me viene a la mente es usar Unsafe # setMemory para poner a cero los búferes que contenían información confidencial en un punto (contraseñas, claves, ...). Incluso podría hacer esto en campos de objetos "inmutables" (por otra parte, supongo que una reflexión antigua también podría ser útil aquí). Sin embargo, no soy un experto en seguridad, así que tómalo con un grano de sal.
fuente
I'd never even heard of this class
... ¡Te lo he dicho muchas veces! suspiro + :(park()
documentación: "Bloquea el subproceso actual, regresando cuando se produce una desconexión de equilibrio, o ya se ha producido una desconexión de equilibrio, o el hilo se interrumpe, o, si no es absoluto y el tiempo no es cero, el dado el tiempo transcurrido nanosegundos, o si es absoluto, la fecha límite dada en milisegundos desde que Epoch ha pasado, o falsamente (es decir, regresando sin 'razón') ". Casi tan bueno como "la memoria se libera cuando el programa sale o, a intervalos aleatorios, lo que ocurra primero".Basado en un análisis muy breve de la biblioteca Java 1.6.12 usando eclipse para el rastreo de referencia, parece que cada funcionalidad útil de
Unsafe
está expuesta de maneras útiles.Las operaciones CAS se exponen a través de las clases Atomic *. Las funciones de manipulación de la memoria se exponen a través de DirectByteBuffer Sync. Las instrucciones (park, unpark) se exponen a través del AbstractQueuedSynchronizer, que a su vez es utilizado por las implementaciones de Lock.
fuente
LockSupport
no AQS (este último es más un bloqueo implícito que park / unpark)Unsafe.throwException : permite lanzar excepciones comprobadas sin declararlas.
Esto es útil en algunos casos en los que se trata de reflexión o AOP.
Suponga que construye un proxy genérico para una interfaz definida por el usuario. Y el usuario puede especificar qué excepción es lanzada por la implicación en un caso especial simplemente declarando la excepción en la interfaz. Entonces, esta es la única manera que sé, de generar una excepción marcada en la Implementación dinámica de la interfaz.
fuente
Thread.stop(Throwable)
sin necesidad de inseguridad, en el mismo hilo puede lanzar cualquier cosa de todos modos (no hay verificación de compilación)UnsupportedOperationException
en el hilo actual a partir de Java 8. Sin embargo, la versión sin argumentos que arrojaThreadDeath
todavía funciona.Un uso de esto es en
java.util.concurrent.atomic
clases:fuente
Para una copia de memoria eficiente (más rápida de copiar que System.arraycopy () para bloques cortos al menos); tal como lo utilizan los códecs Java LZF y Snappy . Usan 'getLong' y 'putLong', que son más rápidos que hacer copias byte a byte; especialmente eficiente al copiar cosas como bloques de 16/32/64 bytes.
fuente
getLong/putLong
(y también tienes que calcular la dirección)getLong
/putLong
: idealmente preferiría laSystem.arraycopy()
simplicidad y todo; pero las pruebas reales mostraron lo contrario para los casos que he probado.Recientemente estuve trabajando en reimplementar la JVM y descubrí que se implementa un sorprendente número de clases en términos de
Unsafe
. La clase está diseñada principalmente para los implementadores de la biblioteca Java y contiene características que son fundamentalmente inseguras pero necesarias para construir primitivas rápidas. Por ejemplo, existen métodos para obtener y escribir desplazamientos de campo sin procesar, mediante sincronización a nivel de hardware, asignación y liberación de memoria, etc. No está destinado a ser utilizado por programadores normales de Java; es indocumentado, específico de implementación e inherentemente inseguro (de ahí el nombre). Además, creo queSecurityManager
no permitirá el acceso a él en casi todos los casos.En resumen, existe principalmente para permitir que los implementadores de la biblioteca accedan a la máquina subyacente sin tener que declarar todos los métodos en ciertas clases como
AtomicInteger
nativo. No debería necesitar usarlo ni preocuparse por él en la programación Java de rutina, ya que el objetivo es hacer que el resto de las bibliotecas sean lo suficientemente rápidas como para no necesitar ese tipo de acceso.fuente
Unsafe.class.getDeclaredField("theUnsafe")
con.setAccessible(true)
y luego.get(null)
va a conseguirlo tambiénÚselo para acceder y asignar grandes cantidades de memoria de manera eficiente, como en su propio motor de vóxel. (es decir, juego de estilo Minecraft).
En mi experiencia, la JVM a menudo no puede eliminar la verificación de límites en el lugar donde realmente la necesita. Por ejemplo, si está iterando sobre una matriz grande, pero el acceso a la memoria real está oculto 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 justo 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.Nosafe para acceder a la memoria directamente, asegurándose de hacer cualquier verificación de límites usted mismo en los lugares correctos. (Usted está gonna comprobación de 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 en particular, porque ha garantizado correctamente que la clase / método / instancia son una combinación de static / final / what-have-you.
Para mi motor de vóxel de cosecha propia, esto resultó en un aumento dramático del rendimiento durante la generación y la serialización de fragmentos (en algunos lugares donde estaba leyendo / escribiendo en toda la matriz de una vez). Los resultados pueden variar, pero si la falta de eliminación de límites es su problema, esto lo solucionará.
Hay algunos problemas potencialmente importantes con esto: específicamente, cuando proporciona la capacidad de acceder a la memoria sin verificar los límites a los clientes de su interfaz, probablemente abusarán de ella. (No olvide que los piratas informáticos también pueden ser clientes de su interfaz ... especialmente en el caso de un motor de vóxel escrito en Java). Por lo tanto, debe diseñar su interfaz de tal manera que no se pueda abusar del acceso a la memoria, o usted debe ser extremadamente cuidadoso para validar datos de usuario antes de que pueda nunca, nunca se mezclan con su interfaz peligroso. Teniendo en cuenta las cosas catastróficas que un pirata informático puede hacer con el acceso a la memoria sin control, probablemente sea mejor adoptar ambos enfoques.
fuente
Las colecciones fuera del montón pueden ser útiles para asignar grandes cantidades de memoria y desasignarla inmediatamente después de su uso sin interferencia de GC. Escribí una biblioteca para trabajar con matrices / listas fuera del montón basadas en
sun.misc.Unsafe
.fuente
Hemos implementado grandes colecciones como Arrays, HashMaps, TreeMaps usando Unsafe.
Y para evitar / minimizar la fragmentación, implementamos un asignador de memoria utilizando los conceptos de dlmalloc sobre inseguro.
Esto nos ayudó a obtener el rendimiento en concurrencia.
fuente
Unsafe.park()
yUnsafe.unpark()
para la construcción de estructuras de control de concurrencia personalizadas y mecanismos de programación cooperativa.fuente
java.util.concurrent.locks.LockSupport
No lo he usado yo mismo, pero supongo que si tiene una variable que solo se lee ocasionalmente en más de un hilo (por lo que realmente no desea que sea volátil), puede usar el
putObjectVolatile
al escribirlo en el hilo principal yreadObjectVolatile
al hacer las lecturas raras de otros hilos.fuente
Lo necesita si necesita reemplazar la funcionalidad proporcionada por una de las clases que la usa actualmente.
Esto puede ser una serialización / deserialización personalizada / más rápida / más compacta, una versión de búfer / redimensionable más rápida / más grande de ByteBuffer, o agregar una variable atómica, por ejemplo, una no admitida actualmente.
Lo he usado para todo esto en algún momento.
fuente
Un ejemplo de su uso es el método aleatorio, que llama a los inseguros a cambiar la semilla .
Este sitio también tiene algunos usos .
fuente
El objeto parece ser la disponibilidad para trabajar a un nivel inferior al que 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 usar la biblioteca insegura, está completando operaciones de bajo nivel que normalmente se realizarían por usted.
Como dijo woliveirajr, "random ()" usa Unsafe para sembrar, al igual que muchas otras operaciones usarán la función allocateMemory () incluida en Unsafe.
Como programador, probablemente podría salirse con la suya sin necesitar esta biblioteca, pero tener un control estricto sobre los elementos de bajo nivel es útil (es por eso que todavía hay ensamblaje y (en menor medida) código C a la deriva en los principales productos)
fuente