Pourquoi sun.misc.Unsafe existe-t-il et comment peut-il être utilisé dans le monde réel?

Je suis tombé sur le package sun.misc.Unsafe l’autre jour et j’ai été surpris de ce qu’il pouvait faire.

Bien sûr, la classe n’est pas documentée, mais je me demandais s’il y avait une bonne raison de l’utiliser. Quels scénarios peuvent survenir où vous auriez besoin de l’utiliser? Comment pourrait-il être utilisé dans un scénario réel?

De plus, si vous en avez besoin, cela n’indique-t-il pas que quelque chose ne va probablement pas dans votre conception?

Pourquoi Java inclut-il même cette classe?

    exemples

    1. VM “insortingnsèque”. c’est-à-dire CAS (Compare-And-Swap) utilisé dans les tables de hachage sans locking, par exemple: sun.misc.Unsafe.compareAndSwapInt il peut faire de vrais appels JNI en code natif contenant des instructions spéciales pour CAS

      En savoir plus sur CAS ici http://en.wikipedia.org/wiki/Compare-and-swap

    2. La fonctionnalité sun.misc.Unsafe de la machine virtuelle hôte peut être utilisée pour allouer des objects non initialisés, puis interpréter l’invocation du constructeur comme tout autre appel de méthode.

    3. On peut suivre les données à partir de l’adresse native.Il est possible de récupérer l’adresse mémoire d’un object en utilisant la classe java.lang.Unsafe, et d’opérer directement sur ses champs via des méthodes get / put peu sûres!

    4. Comstackr les optimisations de temps pour JVM. Haute performance VM utilisant “magic”, nécessitant des opérations de bas niveau. par exemple: http://en.wikipedia.org/wiki/Jikes_RVM

    5. Allocation de mémoire, sun.misc.Unsafe.allocateMemory, par exemple: – Le constructeur DirectByteBuffer l’appelle en interne lorsque ByteBuffer.allocateDirect est appelé

    6. Traçage de la stack d’appel et relecture avec les valeurs instanciées par sun.misc.Unsafe, utile pour l’instrumentation

    7. sun.misc.Unsafe.arrayBaseOffset et arrayIndexScale peuvent être utilisés pour développer des arraylets, une technique permettant de diviser efficacement de grands tableaux en objects plus petits afin de limiter le coût en temps réel de l’parsing, de la mise à jour ou du déplacement des opérations sur des objects volumineux.

    8. 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

    Juste en exécutant une recherche dans un moteur de recherche de code, j’obtiens les exemples suivants:

    • Java Object Notation – utilisez-le pour un traitement plus efficace des tableaux, en citant le javadoc

    Classe simple pour accéder à l’object {@link Unsafe}. {@link Unsafe} * est requirejs pour permettre des opérations CAS efficaces sur les baies. Notez que les versions de {@link java.util.concurrent.atomic}, telles que {@link java.util.concurrent.atomic.AtomicLongArray}, nécessitent des garanties supplémentaires de classement de la mémoire qui ne sont généralement pas nécessaires dans ces algorithmes et sont également coûteuses. sur la plupart des processeurs.

    • SoyLatte – java 6 pour osx javadoc extrait

    / ** Classe de base pour les FieldAccessors basés sur sun.misc.Unsafe pour les champs statiques. L’observation est qu’il n’y a que neuf types de champs du sharepoint vue du code de reflection: les huit types primitifs et Object. L’utilisation de la classe Unsafe à la place des bytecodes générés permet d’économiser de la mémoire et du temps de chargement pour les FieldAccessors générés dynamicment. * /

    • SpikeSource

    / * FinalFields qui sont envoyés à travers le fil .. comment désinstaller et recréer l’object du côté réception? Nous ne voulons pas appeler le constructeur car cela établirait des valeurs pour les champs finaux. Nous devons recréer le champ final exactement comme sur le côté émetteur. Le sun.misc.Unsafe le fait pour nous. * /

    Il y a beaucoup d’autres exemples, suivez simplement le lien ci-dessus …

    Intéressant, je n’avais jamais entendu parler de cette classe (ce qui est probablement une bonne chose).

    Une chose qui me vient à l’esprit est d’utiliser Unsafe # setMemory pour mettre à zéro les tampons contenant des informations sensibles à un moment donné (mots de passe, clés, …). Vous pouvez même le faire avec des champs d’objects “immuables” (encore une fois, je suppose que les vieux reflections peuvent également faire l’affaire). Je ne suis pas expert en sécurité, alors prenez ça avec un grain de sel.

    Unsafe.throwException – permet de lancer une exception vérifiée sans les déclarer.

    Ceci est utile dans certains cas où vous traitez avec la reflection 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 lancée par l’implémentation dans un cas particulier simplement en déclarant l’exception dans l’interface. C’est alors la seule façon que je connaisse, de générer une exception vérifiée dans l’implémentation dynamic de l’interface.

     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("ressortingction") public static void throwUndeclared() { getUnsafe().throwException(new MyException()); } /** * Return an instance of {@link sun.misc.Unsafe}. * @return THE instance */ @SuppressWarnings("ressortingction") 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(); } } 

    Sur la base d’une parsing 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 toutes les fonctionnalités utiles de Unsafe soient exposées 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 DirectByteBuffer Les instructions de synchronisation (park, unpark) sont exposées via AbstractQueuedSynchronizer, qui est lui-même utilisé par les implémentations Lock.

    Classe dangereux

    Une collection de méthodes pour effectuer des opérations de bas niveau et dangereuses. Bien que la classe et toutes les méthodes soient publiques, l’utilisation de cette classe est limitée car seul le code approuvé peut en obtenir des instances.

    Une des utilisations est dans les classes java.util.concurrent.atomic :

    • AtomicIntegerArray
    • AtomicLongArray

    Pour une copie efficace de la mémoire (plus rapide à copier que System.arraycopy () pour les blocs courts au moins); utilisé par les codecs Java LZF et Snappy . Ils utilisent ‘getLong’ et ‘putLong’, qui sont plus rapides que faire des copies octet par octet; particulièrement efficace lors de la copie d’éléments tels que des blocs de 16/32/64 octets.

    Utilisez-le pour accéder et allouer de grandes quantités de mémoire efficacement, comme dans votre propre moteur de voxel! (jeu de style Minecraft)

    D’après mon expérience, la machine virtuelle Java est souvent incapable d’éliminer la vérification des limites lorsque vous en avez vraiment besoin. Par exemple, si vous effectuez une itération sur un grand tableau, mais que l’access réel à la mémoire est inséré sous un appel de méthode non virtuel dans la boucle, la JVM peut toujours effectuer une vérification des limites avec chaque access au tableau la boucle. Ainsi, pour des gains de performances potentiellement importants, vous pouvez éliminer la vérification des limites de la JVM dans la boucle via une méthode qui utilise sun.misc.Unsafe pour accéder directement à la mémoire, en veillant à effectuer toutes les vérifications aux bons endroits. (Vous allez vérifier les chèques à un certain niveau, non?)
    * par non-virtuel, je veux dire que la JVM ne devrait pas avoir à résoudre dynamicment 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 / what-have-you.

    Pour mon moteur de voxel, cela s’est traduit par un gain de performance considérable lors de la génération de blocs et de la sérialisation (peu d’endroits où je lisais / écrivais sur l’ensemble du tableau à la fois). Les résultats peuvent varier, mais si un problème d’élimination des limites est votre problème, cela résoudra le problème.

    Il y a des problèmes potentiellement majeurs avec ceci: spécifiquement, lorsque vous offrez la possibilité d’accéder à la mémoire sans vérifier les 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). Vous devez donc concevoir votre interface de manière à ce que l’access à la mémoire ne soit pas abusif. Vous devez être extrêmement prudent pour valider les données utilisateur avant même qu’elles ne se mêlent à votre dangereuse interface. Considérant les choses catastrophiques qu’un pirate peut faire avec un access mémoire non contrôlé, il est probablement préférable de prendre les deux approches.

    Je travaillais récemment sur la réimplémentation de la JVM et j’ai constaté qu’un nombre surprenant de classes étaient 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 création de primitives rapides. Par exemple, il existe des méthodes pour obtenir et écrire des décalages de champs bruts, utiliser la synchronisation au niveau matériel, allouer et libérer de la mémoire, etc. Il n’est pas conçu pour être utilisé par des programmeurs Java normaux; c’est non documenté, spécifique à la mise en œuvre et insortingnsèquement dangereux (d’où le nom!). De plus, je pense que SecurityManager interdira l’access dans presque tous les cas.

    En bref, il existe principalement pour permettre aux développeurs de bibliothèques 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 préoccuper dans la programmation Java de routine, car le but est de rendre les autres bibliothèques assez rapides pour que vous n’ayez pas besoin de ce type d’access.

    Les collections hors tas peuvent être utiles pour allouer des quantités énormes de mémoire et les libérer immédiatement après utilisation sans interférence du CPG. J’ai écrit une bibliothèque pour travailler avec des tableaux / listes hors tas basés sur sun.misc.Unsafe .

    Unsafe.park() et Unsafe.unpark() pour la construction de structures de contrôle de concurrence personnalisées et de mécanismes de planification coopératifs.

    Nous avons implémenté d’énormes collections comme Arrays, HashMaps, 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 unsafe.
    Cela nous a permis de gagner en performance dans la concurrence.

    Je ne l’ai pas utilisé moi-même, mais je suppose que si vous avez une variable qui n’est que occasionnellement lue par plusieurs threads (vous ne voulez donc pas la rendre volatile), vous pouvez utiliser putObjectVolatile lors de l’écriture dans le thread principal. et readObjectVolatile lors des lectures rares des autres threads.

    Vous en avez besoin si vous devez remplacer la fonctionnalité fournie par l’une des classes qui l’utilise actuellement.

    Cela peut être une sérialisation / désérialisation personnalisée / plus rapide / plus compacte, une version tampon / redimensionnable plus rapide / plus grande de ByteBuffer ou l’ajout d’une variable atomique, par exemple une variable non prise en charge actuellement.

    Je l’ai utilisé pour tous à un moment donné.

    Un exemple de son utilisation est la méthode aléatoire, qui appelle l’incontrôlé pour changer de graine .

    Ce site a également quelques utilisations .

    L’object semble être disponible pour fonctionner à un niveau inférieur à ce que le code Java autorise généralement. Si vous codez une application de haut niveau, la JVM élimine la gestion de la mémoire et les autres opérations du niveau de code afin de faciliter la programmation. En utilisant la bibliothèque Unsafe, vous effectuez efficacement les opérations de bas niveau qui seraient généralement effectuées pour vous.

    Comme woliveirajr a déclaré que “random ()” utilise Unsafe pour générer, de nombreuses autres opérations utiliseront la fonction allocateMemory () incluse dans Unsafe.

    En tant que programmeur, vous pourriez probablement ne plus avoir besoin de cette bibliothèque, mais avoir un contrôle ssortingct sur les éléments de bas niveau est pratique (c’est pourquoi il y a toujours un code assembleur et (dans une moindre mesure) un code C).