Je suis tombé sur le paquet sun.misc.Unsafe l'autre jour et j'ai été étonné de ce qu'il pouvait faire.
Bien sûr, la classe n'est pas documentée, mais je me demandais s'il y avait jamais une bonne raison de l'utiliser. Quels scénarios pourraient survenir où vous auriez besoin de l'utiliser? Comment pourrait-il être utilisé dans un scénario réel?
De plus, si vous le faites besoin, ce que cela n'indique que quelque chose est probablement mal avec votre conception?
Pourquoi Java inclut-il même cette classe?
Réponses:
exemples
«Intrinsification» des VM. c'est-à-dire CAS (Compare-And-Swap) utilisé dans les tables de hachage sans verrouillage, par exemple: sun.misc.Unsafe.compareAndSwapInt, il peut effectuer de vrais appels JNI en code natif qui contient des instructions spéciales pour CAS
en savoir plus sur CAS ici http://en.wikipedia.org/wiki/Compare-and-swap
La fonctionnalité sun.misc.Unsafe de la machine virtuelle hôte peut être utilisée pour allouer des objets non initialisés, puis interpréter l'appel du constructeur comme tout autre appel de méthode.
On peut suivre les données de l'adresse native.Il est possible de récupérer l'adresse mémoire d'un objet en utilisant la classe java.lang.Unsafe, et d'opérer sur ses champs directement via des méthodes get / put dangereuses!
Compilation des optimisations de temps pour JVM. VM haute performance utilisant la «magie», nécessitant des opérations de bas niveau. par exemple: http://en.wikipedia.org/wiki/Jikes_RVM
Allocation de mémoire, sun.misc.Unsafe.allocateMemory, par exemple: - Le constructeur DirectByteBuffer l'appelle en interne lorsque ByteBuffer.allocateDirect est appelé
Traçage de la pile d'appels et relecture avec des valeurs instanciées par sun.misc.Unsafe, utiles pour l'instrumentation
sun.misc.Unsafe.arrayBaseOffset et arrayIndexScale peuvent être utilisés pour développer des arraylets, une technique pour décomposer efficacement les grands tableaux en objets plus petits afin de limiter le coût en temps réel des opérations de scan, de mise à jour ou de déplacement sur les gros objets
http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java
plus sur les références ici - http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html
la source
Juste en exécutant une recherche dans un moteur de recherche de code, j'obtiens les exemples suivants:
Il existe de nombreux autres exemples, suivez simplement le lien ci-dessus ...
la source
Intéressant, je n'avais même jamais entendu parler de ce cours (ce qui est probablement une bonne chose, vraiment).
Une chose qui me vient à l'esprit est d'utiliser Unsafe # setMemory pour mettre à zéro les tampons qui contenaient des informations sensibles à un moment donné (mots de passe, clés, ...). Vous pouvez même le faire pour des champs d'objets "immuables" (là encore, je suppose que la simple réflexion ancienne pourrait faire l'affaire ici aussi). Je ne suis pas un expert en sécurité, alors prenez ceci avec un grain de sel.
la source
I'd never even heard of this class
... Je vous en ai parlé tant de fois! soupir + :(park()
documentation: "Bloquer le thread actuel, qui revient lorsqu'un déséquilibrage se produit, ou qu'un déséquilibrage a déjà eu lieu, ou le thread est interrompu, ou, s'il n'est pas absolu et que l'heure n'est pas nulle, le étant donné que les nanosecondes se sont écoulées, ou si elles sont absolues, le délai donné en millisecondes depuis que Epoch s'est écoulé, ou de façon fallacieuse (c'est-à-dire qu'il revient sans aucune "raison") ". Presque aussi bon que "la mémoire est libérée à la fin du programme ou, à des intervalles aléatoires, selon la première éventualité".Sur la base d'une analyse très brève de la bibliothèque Java 1.6.12 utilisant eclipse pour le traçage de référence, il semble que chaque fonctionnalité utile de
Unsafe
soit exposée de manière utile.Les opérations CAS sont exposées via les classes Atomic *. Les fonctions de manipulation de la mémoire sont exposées via les instructions DirectByteBuffer Sync (parquer, retirer) sont exposées par le biais de AbstractQueuedSynchronizer qui à son tour est utilisé par les implémentations de verrouillage.
la source
LockSupport
non AQS (ce dernier est plus une implication de verrouillage que park /Unsafe.throwException - permet de lever l' exception vérifiée sans les déclarer.
Ceci est utile dans certains cas où vous traitez avec la réflexion ou l'AOP.
Supposons que vous créez un proxy générique pour une interface définie par l'utilisateur. Et l'utilisateur peut spécifier quelle exception est levée par l'implémentation dans un cas spécial simplement en déclarant l'exception dans l'interface. Ensuite, c'est le seul moyen que je connaisse, pour lever une exception vérifiée dans la mise en œuvre dynamique de l'interface.
la source
Thread.stop(Throwable)
sans besoin d'insécurité, dans le même thread, vous pouvez lancer n'importe quoi de toute façon (il n'y a pas de vérification de compilation)UnsupportedOperationException
dans le thread actuel à partir de Java 8. Cependant, la version sans argument qui lèveThreadDeath
fonctionne toujours.Une utilisation de celui-ci est dans les
java.util.concurrent.atomic
classes:la source
Pour une copie mémoire efficace (plus rapide à copier que System.arraycopy () pour les blocs courts au moins); tel qu'utilisé par les codecs Java LZF et Snappy . Ils utilisent «getLong» et «putLong», qui sont plus rapides que de faire des copies octet par octet; particulièrement efficace lors de la copie d'éléments tels que des blocs 16/32/64 octets.
la source
getLong/putLong
(et vous devez également calculer l'adresse)getLong
/putLong
: idéalement, je préférerais laSystem.arraycopy()
simplicité et tout; mais les tests réels ont montré le contraire pour les cas que j'ai testés.Je travaillais récemment sur la réimplémentation de la JVM et j'ai constaté qu'un nombre surprenant de classes sont implémentées en termes de
Unsafe
. La classe est principalement conçue pour les implémenteurs de bibliothèques Java et contient des fonctionnalités qui sont fondamentalement dangereuses mais nécessaires à la construction de primitives rapides. Par exemple, il existe des méthodes pour obtenir et écrire des décalages de champs bruts, en utilisant la synchronisation au niveau matériel, allouer et libérer de la mémoire, etc. Elle n'est pas destinée à être utilisée par les programmeurs Java normaux; il est non documenté, spécifique à l'implémentation et intrinsèquement dangereux (d'où le nom!). De plus, je pense que laSecurityManager
volonté d'interdire l'accès à celui-ci dans presque tous les cas.En bref, il existe principalement pour permettre aux implémenteurs de bibliothèque d'accéder à la machine sous-jacente sans avoir à déclarer chaque méthode dans certaines classes comme
AtomicInteger
native. Vous ne devriez pas avoir besoin de l'utiliser ou de vous en soucier dans la programmation Java de routine, car le but est de rendre le reste des bibliothèques assez rapide pour que vous n'ayez pas besoin de ce type d'accès.la source
Unsafe.class.getDeclaredField("theUnsafe")
avec.setAccessible(true)
et.get(null)
l'obtiendra aussiUtilisez-le pour accéder et allouer efficacement de grandes quantités de mémoire, comme dans votre propre moteur voxel! (c'est-à-dire un jeu de style Minecraft.)
D'après mon expérience, la JVM est souvent incapable d'éliminer la vérification des limites là où vous en avez vraiment besoin. Par exemple, si vous parcourez un grand tableau, mais que l'accès à la mémoire réel est caché sous un appel de méthode non virtuel * dans la boucle, la JVM peut toujours effectuer une vérification des limites avec chaque accès au tableau, plutôt qu'une seule fois juste avant la boucle. Ainsi, pour des gains de performances potentiellement importants, vous pouvez éliminer la vérification des limites JVM à l'intérieur de la boucle via une méthode qui utilise sun.misc.Unsafe pour accéder directement à la mémoire, en vous assurant d'effectuer vous-même les limites aux bons endroits. (Vous êtes Gonna bornes vérifier à un certain niveau, non?)
* par non virtuel, je veux dire que la JVM ne devrait pas avoir à résoudre dynamiquement quelle que soit votre méthode particulière, car vous avez correctement garanti que la classe / méthode / instance est une combinaison de statique / final / ce que vous avez.
Pour mon moteur de voxel maison, cela a entraîné un gain de performances spectaculaire lors de la génération et de la sérialisation des blocs (aux endroits où je lisais / écrivais sur l'ensemble de la baie à la fois). Les résultats peuvent varier, mais si le manque d'élimination des limites est votre problème, cela le corrigera.
Il y a des problèmes potentiellement majeurs avec cela: en particulier, lorsque vous fournissez la possibilité d'accéder à la mémoire sans vérification des limites aux clients de votre interface, ils en abuseront probablement. (N'oubliez pas que les pirates peuvent également être des clients de votre interface ... en particulier dans le cas d'un moteur voxel écrit en Java.) Ainsi, vous devez soit concevoir votre interface de manière à ce que l'accès à la mémoire ne puisse pas être abusé, ou vous devez être extrêmement prudent pour valider les données utilisateur avant qu'elles ne puissent jamais, jamais se mélanger avec votre interface dangereuse. Compte tenu des choses catastrophiques qu'un pirate peut faire avec un accès mémoire non contrôlé, il est probablement préférable d'adopter les deux approches.
la source
Les collections hors segment peuvent être utiles pour allouer d'énormes quantités de mémoire et la désallouer immédiatement après utilisation sans interférence GC. J'ai écrit une bibliothèque pour travailler avec des tableaux / listes hors tas basés sur
sun.misc.Unsafe
.la source
Nous avons implémenté d'énormes collections comme des tableaux, des HashMaps, des TreeMaps en utilisant Unsafe.
Et pour éviter / minimiser la fragmentation, nous avons implémenté l'allocateur de mémoire en utilisant les concepts de dlmalloc sur dangereux.
Cela nous a aidés à gagner en performance en simultanéité.
la source
Unsafe.park()
etUnsafe.unpark()
pour la construction de structures de contrôle de simultanéité personnalisées et de mécanismes de planification coopératifs.la source
java.util.concurrent.locks.LockSupport
Je ne l'ai pas utilisé moi-même, mais je suppose que si vous avez une variable qui n'est lue qu'occasionnellement par plusieurs threads (donc vous ne voulez pas vraiment la rendre volatile), vous pouvez utiliser le
putObjectVolatile
lorsque vous l'écrivez dans le thread principal etreadObjectVolatile
lors de la lecture des rares autres threads.la source
Vous en avez besoin si vous devez remplacer les fonctionnalités fournies par l'une des classes qui l'utilisent actuellement.
Cela peut être une sérialisation / désérialisation personnalisée / plus rapide / plus compacte, une version plus rapide / plus grande du tampon / redimensionnable de ByteBuffer, ou l'ajout d'une variable atomique, par exemple une variable non prise en charge actuellement.
Je l'ai utilisé pour tout cela à un moment donné.
la source
Un exemple de son utilisation est la méthode aléatoire, qui appelle le dangereux pour changer la graine .
Ce site en a également quelques utilisations .
la source
L'objet semble être la disponibilité pour fonctionner à un niveau inférieur à ce que le code Java permet généralement. Si vous codez une application de haut niveau, la JVM résume la gestion de la mémoire et d'autres opérations à l'écart du niveau de code, ce qui facilite la programmation. En utilisant la bibliothèque Unsafe, vous effectuez efficacement des opérations de bas niveau qui seraient généralement effectuées pour vous.
Comme l'a dit woliveirajr, "random ()" utilise Unsafe pour amorcer tout comme de nombreuses autres opérations utiliseront la fonction allocateMemory () incluse dans Unsafe.
En tant que programmeur, vous pourriez probablement vous en tirer sans avoir besoin de cette bibliothèque, mais avoir un contrôle strict sur les éléments de bas niveau est très pratique (c'est pourquoi il y a toujours de l'assembly et (dans une moindre mesure) du code C qui dérive dans les principaux produits)
la source