it-swarm.com.de

Warum gibt es Sun.misc.Unsafe und wie kann es in der realen Welt verwendet werden?

Ich bin neulich auf das Sun.misc.Unsafe-Paket gestoßen und war erstaunt, was es alles kann.

Natürlich ist die Klasse nicht dokumentiert, aber ich habe mich gefragt, ob es jemals einen guten Grund gibt, sie zu benutzen. Welche Szenarien könnten auftreten, wenn Sie es verwenden müssten? Wie könnte es in einem realen Szenario eingesetzt werden?

Wenn Sie tun es benötigen, bedeutet das dann nicht, dass wahrscheinlich etwas mit Ihrem Design nicht stimmt?

Warum enthält Java sogar diese Klasse?

263
pdeva

beispiele

  1. VM "Intrinsification". Das heißt, CAS (Compare-And-Swap), das in sperrenfreien Hash-Tabellen verwendet wird, z

    lesen Sie mehr über CAS hier http://en.wikipedia.org/wiki/Compare-and-swap

  2. Die Sun.misc.Unsafe-Funktionalität des Hosts VM) kann verwendet werden, um nicht initialisierte Objekte zuzuweisen und den Konstruktoraufruf dann wie jeden anderen Methodenaufruf zu interpretieren.

  3. Man kann die Daten von der nativen Adresse aus verfolgen. Es ist möglich, die Speicheradresse eines Objekts mit der Java.lang.Unsafe-Klasse abzurufen und seine Felder direkt mit unsicheren get/put-Methoden zu bearbeiten!

  4. Zeitoptimierungen für JVM kompilieren. Hohe Leistung VM mit "Magie", erfordert Operationen auf niedriger Ebene. Beispiel: http://en.wikipedia.org/wiki/Jikes_RVM

  5. Zuweisen von Speicher, Sun.misc.Unsafe.allocateMemory, z. B .: - Der DirectByteBuffer-Konstruktor ruft ihn intern auf, wenn ByteBuffer.allocateDirect aufgerufen wird

  6. Verfolgen des Aufrufstapels und Wiedergeben mit Werten, die von Sun.misc.Unsafe instanziiert wurden. Nützlich für die Instrumentierung

  7. Sun.misc.Unsafe.arrayBaseOffset und arrayIndexScale können zum Entwickeln von Arraylets verwendet werden, einer Technik zum effizienten Aufteilen großer Arrays in kleinere Objekte, um die Echtzeitkosten für das Scannen, Aktualisieren oder Verschieben großer Objekte zu begrenzen

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

weitere Referenzen finden Sie hier - http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html

156
zudokod

Nur durch Ausführen einer Suche in einigen Code-Suchmaschinen erhalte ich die folgenden Beispiele:

  • Java Object Notation - Verwenden Sie es für eine effizientere Array-Verarbeitung unter Angabe des Javadoc

Einfache Klasse, um Zugriff auf das {@link Unsafe} -Objekt zu erhalten. {@link Unsafe} * ist erforderlich, um effiziente CAS-Operationen auf Arrays zu ermöglichen. Beachten Sie, dass die Versionen in {@link Java.util.concurrent.atomic}, z. B. {@link Java.util.concurrent.atomic.AtomicLongArray}, zusätzliche Garantien für die Speicherreihenfolge erfordern, die in diesen Algorithmen im Allgemeinen nicht benötigt werden und auch teuer sind auf den meisten Prozessoren.

  • SoyLatte - Java 6 für osx javadoc-Auszug

/ ** Basisklasse für Sun.misc.Unsafe-basierte FieldAccessors für statische Felder. Die Beobachtung ist, dass es vom Standpunkt des Reflexionscodes nur neun Arten von Feldern gibt: die acht primitiven Typen und Objekt. Die Verwendung der Klasse Unsafe anstelle von generierten Bytecodes spart Speicher und Ladezeit für die dynamisch generierten FieldAccessors. * /

  • SpikeSource

/ * FinalFields, die über die Leitung gesendet werden. Wie kann das Objekt auf der Empfängerseite dekomprimiert und neu erstellt werden? Wir möchten den Konstruktor nicht aufrufen, da er Werte für endgültige Felder festlegt. Wir müssen das endgültige Feld genauso neu erstellen, wie es auf der Absenderseite war. Die Sun.misc.Unsafe erledigt dies für uns. * /

Es gibt viele andere Beispiele, folgen Sie einfach dem obigen Link ...

31
Asaf

Interessant, ich hatte noch nie von dieser Klasse gehört (was wahrscheinlich wirklich eine gute Sache ist).

Eine Sache, die einem in den Sinn kommt, ist die Verwendung von nsafe # setMemory , um Puffer zu nullen, die an einem Punkt vertrauliche Informationen enthielten (Passwörter, Schlüssel, ...). Sie können dies sogar für Felder mit "unveränderlichen" Objekten tun (ich nehme wieder an, dass auch hier einfache alte Überlegungen den Trick machen könnten). Ich bin allerdings kein Sicherheitsexperte, nehmen Sie dies mit einem Körnchen Salz.

24
Mike Daniels

Basierend auf einer sehr kurzen Analyse der Java 1.6.12 Bibliothek unter Verwendung von Eclipse zur Referenzverfolgung, scheint es, als ob jede nützliche Funktionalität von Unsafe auf nützliche Weise verfügbar gemacht wird.

CAS-Operationen werden über die Atomic * -Klassen verfügbar gemacht. Speicherbearbeitungsfunktionen werden durch DirectByteBuffer Sync-Anweisungen (Parken, Entparken) verfügbar gemacht, die durch den AbstractQueuedSynchronizer verfügbar gemacht werden, der wiederum von Lock-Implementierungen verwendet wird.

22
Tim Bender

nsafe.throwException - Ermöglicht das Auslösen einer aktivierten Ausnahme, ohne diese zu deklarieren.

Dies ist in einigen Fällen nützlich, in denen Sie sich mit Reflexion oder AOP befassen.

Angenommen, Sie erstellen einen generischen Proxy für eine benutzerdefinierte Schnittstelle. Und der Benutzer kann angeben, welche Ausnahme in einem bestimmten Fall von der Implementierung ausgelöst wird, indem er die Ausnahme in der Schnittstelle deklariert. Dann ist dies die einzige mir bekannte Möglichkeit, eine aktivierte Ausnahme in der dynamischen Implementierung der Schnittstelle auszulösen.

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

Klasse nsicher

Eine Sammlung von Methoden zum Ausführen unsicherer Operationen auf niedriger Ebene. Obwohl die Klasse und alle Methoden öffentlich sind, ist die Verwendung dieser Klasse beschränkt, da nur vertrauenswürdiger Code Instanzen davon abrufen kann.

Eine Verwendung davon ist in Java.util.concurrent.atomic Klassen:

10
Margus

Für eine effiziente Speicherkopie (schneller zu kopieren als System.arraycopy (), zumindest für kurze Blöcke); wie von Java LZF und Snappy verwendet. Sie verwenden 'getLong' und 'putLong' ', die schneller sind als das Kopieren von Bytes, besonders effizient beim Kopieren von 16/32/64-Byte-Blöcken.

6
StaxMan

Ich habe kürzlich an der Neuimplementierung der JVM gearbeitet und festgestellt, dass eine überraschende Anzahl von Klassen in Bezug auf Unsafe implementiert ist. Die Klasse ist hauptsächlich für die Java - Bibliotheksimplementierer konzipiert und enthält Funktionen, die grundsätzlich unsicher sind, aber für die Erstellung schneller Grundelemente erforderlich sind. Beispielsweise gibt es Methoden zum Abrufen und Schreiben von Rohfeld-Offsets, zum Synchronisieren auf Hardwareebene, zum Zuweisen und Freigeben von Speicher usw. Sie sind nicht für normale Java - Programmierer vorgesehen. Es ist undokumentiert, implementierungsspezifisch und von Natur aus unsicher (daher der Name!). Außerdem denke ich, dass der SecurityManager in fast allen Fällen den Zugriff darauf verweigert.

Kurz gesagt, es besteht hauptsächlich darin, Bibliotheksimplementierern den Zugriff auf den zugrunde liegenden Computer zu ermöglichen, ohne dass jede Methode in bestimmten Klassen wie AtomicInteger native deklariert werden muss. Sie sollten sich bei der Routineprogrammierung Java nicht darum kümmern müssen, da es darauf ankommt, den Rest der Bibliotheken so schnell zu machen, dass Sie keinen solchen Zugriff benötigen.

5
templatetypedef

Verwenden Sie es, um effizient auf große Speichermengen zuzugreifen und diese zuzuweisen, beispielsweise in Ihrer eigenen Voxel-Engine! (d. h. Spiel im Minecraft-Stil.)

Nach meiner Erfahrung ist die JVM häufig nicht in der Lage, die Überprüfung von Grenzen an der Stelle zu verhindern, an der Sie sie wirklich benötigen. Wenn Sie beispielsweise über ein großes Array iterieren, sich der tatsächliche Speicherzugriff jedoch unter einem nicht virtuellen Methodenaufruf in der Schleife befindet, führt die JVM möglicherweise immer noch eine Begrenzungsprüfung bei jedem Arrayzugriff durch und nicht nur einmal die Schleife. Für potenziell große Leistungssteigerungen können Sie die JVM-Begrenzungsüberprüfung in der Schleife mit einer Methode eliminieren, die Sun.misc.Unsafe verwendet, um direkt auf den Speicher zuzugreifen, und dabei sicherstellen, dass Sie die Begrenzungsüberprüfung selbst an den richtigen Stellen durchführen. (Sie werden auf einer bestimmten Ebene prüfen, oder?)
* Mit nicht-virtuell meine ich, dass die JVM nicht dynamisch aufgelöst werden muss, unabhängig davon, um welche Methode es sich handelt, da Sie korrekt garantiert haben, dass Klasse/Methode/Instanz eine Kombination aus statisch/final/what-have-you ist.

Für meine selbst gebaute Voxel-Engine führte dies zu einem dramatischen Leistungszuwachs bei der Chunk-Generierung und Serialisierung (an einigen Stellen, an denen ich auf einmal auf dem gesamten Array gelesen/geschrieben habe). Die Ergebnisse können unterschiedlich ausfallen. Wenn Sie jedoch Probleme mit der Beseitigung von Grenzen haben, wird dies behoben.

Dies kann zu einigen schwerwiegenden Problemen führen: Wenn Sie den Zugriff auf den Speicher ermöglichen, ohne die Clients Ihrer Schnittstelle auf Grenzen zu prüfen, wird dieser wahrscheinlich missbraucht. (Vergessen Sie nicht, dass Hacker auch Clients Ihrer Benutzeroberfläche sein können ... insbesondere im Fall einer in Java geschriebenen Voxel-Engine.) Daher sollten Sie Ihre Benutzeroberfläche entweder so gestalten, dass der Speicherzugriff nicht missbraucht werden kann, oder Sie sollten äußerst vorsichtig sein, um Benutzerdaten zu validieren, bevor sie sich jemals jemals mit Ihrer gefährlichen Schnittstelle vermischen können. Angesichts der katastrophalen Auswirkungen, die ein Hacker auf den ungeprüften Speicherzugriff haben kann, ist es wahrscheinlich am besten, beide Ansätze zu wählen.

5
Philip

Wir haben riesige Sammlungen wie Arrays, HashMaps, TreeMaps mit Unsafe implementiert.
Um die Fragmentierung zu vermeiden/zu minimieren, haben wir den Speicherzuweiser mit den Konzepten dlmalloc over unsafe implementiert.
Dies hat uns geholfen, die Leistung im Parallelbetrieb zu steigern.

4
pradipmw

Off-Heap-Sammlungen können nützlich sein, um große Mengen an Speicher zuzuweisen und die Zuordnung unmittelbar nach der Verwendung ohne GC-Interferenz aufzuheben. Ich habe ein Bibliothek für die Arbeit mit Off-Heap-Arrays/Listen geschrieben, die auf Sun.misc.Unsafe Basieren.

4
alexkasko

Unsafe.park() und Unsafe.unpark() für den Aufbau von benutzerdefinierten Parallelitätskontrollstrukturen und kooperativen Planungsmechanismen.

3
andersoj
1
woliveirajr

Sie benötigen es, wenn Sie Funktionen ersetzen möchten, die von einer der Klassen bereitgestellt werden, die es derzeit verwenden.

Dies kann eine benutzerdefinierte/schnellere/kompaktere Serialisierung/Deserialisierung, eine schnellere/größere Puffer-/Größenänderungsversion von ByteBuffer oder das Hinzufügen einer atomaren Variablen sein, z. Eine wird derzeit nicht unterstützt.

Ich habe es irgendwann für all diese verwendet.

1
Peter Lawrey

Ich habe es nicht selbst verwendet, aber ich nehme an, wenn Sie eine Variable haben, die nur gelegentlich von mehr als einem Thread gelesen wird (damit Sie es nicht wirklich flüchtig machen wollen), können Sie beim Schreiben das putObjectVolatile verwenden es im Hauptthread und readObjectVolatile, wenn die seltenen Lesevorgänge von anderen Threads ausgeführt werden.

1

Bei dem Objekt scheint es sich um eine Verfügbarkeit zu handeln, die niedriger ist als normalerweise in Java) vorgesehen. Wenn Sie eine Anwendung auf hoher Ebene codieren, abstrahiert die JVM die Speicherbehandlung und andere Vorgänge von der Code-Level, damit es einfacher zu programmieren ist: Mit der Unsafe-Bibliothek führen Sie effektiv Vorgänge auf niedriger Ebene aus, die normalerweise für Sie durchgeführt werden.

Wie woliveirajr feststellte, verwendet random () Unsafe, um einen Seed zu erstellen, genauso wie viele andere Operationen die Funktion allocateMemory () verwenden, die in Unsafe enthalten ist.

Als Programmierer könnten Sie wahrscheinlich davonkommen, diese Bibliothek niemals zu benötigen, aber eine strikte Kontrolle über Elemente auf niedriger Ebene ist praktisch (deshalb gibt es in wichtigen Produkten immer noch Assembly- und (in geringerem Maße) C-Code).

0
Grambot