270 votes

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, cette classe n'est pas documentée, mais je me demandais s'il y avait une bonne raison de l'utiliser. Quels scénarios pourraient se présenter où vous auriez besoin de l'utiliser ? Comment pourrait-elle être utilisée dans un scénario du monde réel ?

En outre, si vous faire 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 cette classe ?

7 votes

Les développeurs du JDK examinent actuellement cette API en vue de sa transformation éventuelle en API publique dans Java 9. Si vous l'utilisez, cela vaut la peine de prendre 5 minutes pour remplir le questionnaire : surveyymonkey.com/sun-misc-Unsafe .

2 votes

Ce message est discuté sur meta : meta.stackoverflow.com/questions/299139/

160voto

hGx Points 2521

Exemples

  1. Intrinsification" de la VM. Par exemple, CAS (Compare-And-Swap) est utilisé dans les tables de hachage sans verrouillage. ex : sun.misc.Unsafe.compareAndSwapInt il peut faire de vrais appels JNI dans du code natif qui contient des instructions spéciales pour CAS.

    Pour en savoir plus sur le CAS, cliquez ici http://en.wikipedia.org/wiki/Compare-and-swap

  2. La fonctionnalité sun.misc.Unsafe de la VM hôte peut être utilisée pour allouer des objets non initialisés et ensuite 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 objet en utilisant 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 en temps de compilation pour la JVM. VM très performante utilisant la "magie", nécessitant des opérations de bas niveau. par ex : http://en.wikipedia.org/wiki/Jikes_RVM

  5. Allocation de mémoire, sun.misc.Unsafe.allocateMemory Exemple : le constructeur de DirectByteBuffer l'appelle en interne lorsque ByteBuffer.allocateDirect est invoqué.

  6. Tracer la pile d'appels et rejouer 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 les arraylets, une technique permettant de diviser efficacement les grands tableaux en objets plus petits afin de limiter le coût en temps réel des opérations de balayage, de mise à jour ou de déplacement sur les grands objets.

  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

1 votes

Si vous obtenez l'adresse d'un champ en utilisant Unsafe, elle peut toujours être modifiée par le GC, donc cette opération n'est-elle pas plutôt inutile ?

0 votes

Obtenir l'adresse de ceux que vous avez attribués

0 votes

Que voulez-vous dire exactement par celui I Cette fonction semble être utilisée là où les objets ont été créés à l'aide de l'opérateur "new", d'où ma question.

31voto

Asaf Points 3203

Juste en faisant un recherche dans un moteur de recherche de code, j'obtiens les exemples suivants :

Classe simple permettant d'obtenir l'accès à l'objet {@link Unsafe}. {@link Unsafe} * est nécessaire pour permettre des opérations CAS efficaces sur les tableaux. Notez que les versions de {@link java.util.concurrent.atomic}, telles que {@link java.util.concurrent.atomic.AtomicLongArray}, requièrent des garanties d'ordonnancement de la mémoire supplémentaires d'ordonnancement de la mémoire qui ne sont généralement pas nécessaires dans ces coûteux sur la plupart des processeurs.

  • SoyLatte - java 6 pour osx extrait de javadoc

/** Classe de base pour sun.misc.Unsafe-based FieldAccessors pour les champs statiques. statiques. Le constat est qu'il n'existe que neuf types de du point de vue du code de réflexion : les huit types primitifs et les et Object. L'utilisation de la classe Unsafe au lieu des bytecodes générés permet d'économiser de la mémoire et du temps de chargement pour la classe Unsafe. FieldAccessors générés dynamiquement. */

  • SpikeSource

/* FinalFields qui sont envoyés à travers le fil comment démarshall et recréer l'objet sur le côté récepteur ? Nous ne voulons pas invoquer le constructeur puisqu'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 fait cela pour nous. */

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

25voto

Mike Daniels Points 5729

Intéressant, je n'avais jamais entendu parler de ce cours (ce qui est probablement une bonne chose, vraiment).

Une chose qui me vient à l'esprit est d'utiliser Non sûr#setMemory pour remettre à zéro les tampons qui contenaient des informations sensibles à un moment donné (mots de passe, clés, ...). Vous pourriez même le faire pour les champs d'objets "immuables" (mais je suppose que la bonne vieille réflexion pourrait aussi faire l'affaire). Je ne suis pas un expert en sécurité, alors prenez tout cela avec des pincettes.

4 votes

I'd never even heard of this class ... Je vous en ai parlé tant de fois ! soupir + :(

7 votes

Cela ne servirait à rien, puisque Java utilise un collecteur de déchets générationnel et que vos informations sensibles se trouvent probablement déjà quelque part dans la mémoire "libre", attendant d'être écrasées.

39 votes

Jamais entendu parler non plus, mais j'adore leur park() documentation : "Bloque le fil d'exécution actuel, retournant lorsqu'un décollage d'équilibrage se produit, ou qu'un décollage d'équilibrage s'est déjà produit, ou que le fil d'exécution est interrompu, ou, si ce n'est pas absolu et que le temps n'est pas égal à zéro, le temps donné en nanosecondes s'est écoulé, ou si c'est absolu, le délai donné en millisecondes depuis que l'époque est passée, ou fallacieusement (c'est-à-dire qu'ils reviennent sans raison). ". Presque aussi bien que "la mémoire est libérée lorsque le programme se termine, ou à des intervalles aléatoires, selon ce qui se produit en premier".

22voto

Tim Bender Points 11611

Sur la base d'une très brève analyse de la bibliothèque Java 1.6.12 en utilisant eclipse pour le traçage des références, il semble que toutes les fonctionnalités utiles de l'outil Unsafe est exposée de manière utile.

Les opérations CAS sont exposées à travers les classes Atomic*. Les fonctions de manipulation de la mémoire sont exposées par le biais de DirectByteBuffer. Les instructions de synchronisation (park, unpark) sont exposées à travers l'AbstractQueuedSynchronizer qui, à son tour, est utilisé par les implémentations de Lock.

0 votes

Les AtomicXXXUpdaters sont trop lents et quand on en a vraiment besoin : CAS - vous ne pouvez pas vous permettre de les utiliser en fait. Si vous faites du métal, vous n'utiliserez pas les niveaux d'abstraction et les nombreux contrôles. L'échec du CAS est une mauvaise chose dans une boucle, en particulier lorsque le matériel décide de mal prédire la branche (en raison d'une forte contention), mais avoir quelques comparaisons/branches supplémentaires n'est pas bon. Le Park/Unpark est exposé à travers LockSupport pas AQS (ce dernier est plus une impl. de verrouillage que le parking/déverrouillage)

21voto

Ralph Points 42744

Unsafe.throwException - permet de lancer des exceptions vérifiées sans les déclarer.

Ceci est utile dans certains cas où vous traitez de la réflexion ou de la POA.

Supposons que vous construisiez 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 particulier, en déclarant simplement l'exception dans l'interface. Alors c'est la seule façon que je connaisse, pour lever une exception vérifiée dans l'implémentation 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();
    }
}

14 votes

Vous pouvez faire la même chose avec Thread.stop(Throwable) pas besoin de unsafe, dans le même thread vous pouvez lancer n'importe quoi de toute façon (il n'y a pas de contrôle de compilation)

0 votes

Vous pouvez le faire uniquement par le biais du bytecode (ou utiliser Lomboc pour le faire pour vous).

1 votes

@bestsss Cette méthode a été supprimée et lance un message d'erreur. UnsupportedOperationException dans le fil d'exécution actuel à partir de Java 8. Cependant, la version sans argument qui lance la commande ThreadDeath fonctionne toujours.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X