web-dev-qa-db-fra.com

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

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, le cours n’est pas documenté, mais je me demandais s’il existait 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 en avez besoin , cela ne signifie-t-il pas que quelque chose ne va pas dans votre conception?

Pourquoi Java inclut-il même cette classe?

263
pdeva

exemples

  1. VM "intrinsèque". 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 véritables 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 l'hôte VM 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.

  3. Vous pouvez suivre les données à partir de l’adresse native. Il est possible de récupérer l’adresse mémoire d’un objet à l’aide de la classe Java.lang.Unsafe, et d’opérer sur ses champs directement via des méthodes get/put non sécurisées!

  4. Optimisations du temps de compilation pour JVM. Performances élevées VM utilisant "la magie", nécessitant des opérations de bas niveau. 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 pile d'appels et relecture avec les valeurs instanciées par Sun.misc.Unsafe, utiles pour l'instrumentation

  7. Sun.misc.Unsafe.arrayBaseOffset et arrayIndexScale peuvent être utilisés pour développer des tableaux, une technique permettant de fractionner efficacement des tableaux de grande taille en objets plus petits afin de limiter les coûts d'analyse, de mise à jour ou de déplacement des objets volumineux.

  8. http://robaustin.wikidot.com/how-to-write-todirect-memory-locations-in-Java

plus sur les références ici - http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html

156
zudokod

Juste en exécutant un recherche dans un moteur de recherche de code, je reçois les exemples suivants:

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

Classe simple pour obtenir l'accès à l'objet {@link Unsafe}. {@link Unsafe} * est requis 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 d'ordonnancement 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 l'extrait osx javadoc

/ ** 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 point de vue du code de réflexion: les huit types primitifs et Object. L'utilisation de la classe Unsafe au lieu des octets générés économise de la mémoire et du temps de chargement pour les FieldAccessors générés dynamiquement. * /

  • SpikeSource

/ * FinalFields qui sont envoyés de bout en bout. Comment annuler la fusion et recréer l’objet du côté réception? Nous ne voulons pas invoquer le constructeur car il établirait des valeurs pour les champs finaux. Nous devons recréer le champ final exactement comme il était du côté de l'expéditeur. Le Sun.misc.Unsafe le fait pour nous. * /

Il existe de nombreux autres exemples, il suffit de suivre le lien ci-dessus ...

31
Asaf

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 nsafe # setMemory pour mettre à zéro les mémoires tampons contenant des informations sensibles en un point (mots de passe, clés, ...). Vous pouvez même faire cela pour des champs d'objets "immuables" (encore une fois, je suppose que de vieilles réflexions pourraient faire l'affaire ici aussi). Je ne suis pas un expert en sécurité, alors prenez ceci avec un grain de sel.

24
Mike Daniels

Basé sur une très brève analyse 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 mémoire sont exposées via DirectByteBuffer. Les instructions de synchronisation (park, unpark) sont exposées via AbstractQueuedSynchronizer, qui est à son tour utilisé par les implémentations de Lock.

22
Tim Bender

nsafe.throwException - permet de lever une exception cochée sans la déclarer.

Ceci est utile dans certains cas où vous traitez avec réflexion ou AOP.

Supposons que vous construisez 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.

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();
    }
}
21
Ralph

Classe non sécurisé

Ensemble de méthodes permettant d'effectuer des opérations dangereuses de niveau inférieur. 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 utilisation de celui-ci est dans Java.util.concurrent.atomic Des classes:

10
Margus

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

6
StaxMan

Je travaillais récemment sur la réimplémentation de la machine virtuelle Java 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èque Java) et contient des fonctionnalités fondamentalement peu sûres mais nécessaires pour la construction de primitives rapides. Par exemple, il existe des méthodes pour obtenir et écrire des décalages de champs bruts, en utilisant du matériel. synchronisation de niveau, allocation et libération de mémoire, etc. Il n’est pas destiné à être utilisé par les programmeurs normaux Java; il est non documenté, spécifique à l’implémentation et intrinsèquement dangereux (d’où le nom!). Je pense que le SecurityManager en interdira l'accès 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 toutes les méthodes de certaines classes comme AtomicInteger native. Vous ne devriez pas avoir besoin de l'utiliser ou de vous en préoccuper dans la programmation Java), 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.

5
templatetypedef

Utilisez-le pour accéder à de grandes quantités de mémoire et les allouer efficacement, 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 en place, vous en avez vraiment besoin. Par exemple, si vous effectuez une itération sur un grand tableau, mais que l'accès réel à la mémoire est dissimulé sous un appel de méthode non virtuel * dans la boucle, la machine virtuelle Java peut toujours effectuer une vérification des limites avec chaque accès au tableau, plutôt qu'une fois juste avant. la boucle. Ainsi, pour des gains de performances potentiellement importants, vous pouvez éliminer la vérification des limites de la machine virtuelle Java à l'intérieur de la boucle via une méthode qui utilise Sun.misc.Unsafe pour accéder directement à la mémoire, en veillant à bien vérifier les limites vous-même aux endroits appropriés. (Vous êtes allez vérifier à un certain niveau, non?)
* par non-virtuel, je veux dire que la machine virtuelle Java ne devrait pas avoir à résoudre dynamiquement quelle que soit votre méthode particulière, car vous avez correctement garanti que classe/méthode/instance est une combinaison de static/final/what-have-you.

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

Cela risque de poser certains problèmes majeurs: 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 ... particulièrement 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 utilisé de manière abusive, ou vous devez être extrêmement prudent pour valider les données utilisateur avant qu'elles ne puissent jamais, jamais se mêler à votre interface dangereuse. Compte tenu des conséquences catastrophiques qu'un pirate informatique peut faire avec un accès non contrôlé à la mémoire, il est probablement préférable de prendre les deux approches.

5
Philip

Nous avons implémenté d'énormes collections telles que Arrays, HashMaps, TreeMaps utilisant Unsafe.
Et pour éviter/minimiser la fragmentation, nous avons mis en oeuvre un allocateur de mémoire utilisant les concepts de dlmalloc sur unsafe.
Cela nous a permis d’obtenir des performances en simultanéité.

4
pradipmw

Les collections off-tas peuvent être utiles pour allouer d'énormes quantités de mémoire et la désallouer immédiatement après utilisation, sans interférence de la part du GC. J'ai écrit un bibliothèque pour travailler avec des tableaux/listes off-tas basés sur Sun.misc.Unsafe.

4
alexkasko

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.

3
andersoj

Un exemple de son utilisation est la méthode aléatoire, qui appelle le non sécurisé pour changer le germe .

Ce site a aussi quelques utilisations .

1
woliveirajr

Vous en aurez 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 plus rapide/plus grande du tampon/redimensionnable de ByteBuffer, ou l'ajout d'une variable atomique, par ex. un n'est pas supporté actuellement.

Je l'ai utilisé pour tout cela à un moment donné.

1
Peter Lawrey

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 plus d'un thread (vous ne voulez donc pas vraiment la rendre volatile), vous pouvez utiliser le putObjectVolatile lors de l'écriture dans le thread principal et readObjectVolatile lors de lectures rares à partir d’autres threads.

1

L’objet semble être disponible 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 les autres opérations En utilisant la bibliothèque Unsafe, vous effectuez efficacement des opérations de bas niveau qui seraient normalement effectuées pour vous.

Comme le dit woliveirajr, "random ()" utilise Unsafe pour créer de la même façon que de nombreuses autres opérations utiliseront la fonction allocateMemory () incluse dans Unsafe.

En tant que programmeur, vous n’auriez probablement jamais besoin de cette bibliothèque, mais avoir un contrôle strict sur les éléments de bas niveau est utile (c’est pourquoi il reste toujours du code Assembly et (dans une moindre mesure) dérivant dans les principaux produits).

0
Grambot