Ich bin neulich auf das Paket sun.misc.Unsafe gestoßen und war erstaunt, was es tun kann.
Natürlich ist die Klasse nicht dokumentiert, aber ich habe mich gefragt, ob es jemals einen guten Grund gibt, sie zu verwenden. Welche Szenarien könnten auftreten, wenn Sie es verwenden müssten? Wie könnte es in einem realen Szenario verwendet werden?
Wenn Sie es brauchen, bedeutet das nicht, dass wahrscheinlich etwas mit Ihrem Design nicht stimmt?
Warum enthält Java diese Klasse überhaupt?
Antworten:
Beispiele
VM "Intrinsification". dh CAS (Compare-And-Swap), das in sperrenfreien Hash-Tabellen verwendet wird, z. B.: sun.misc.Unsafe.compareAndSwapInt, kann echte JNI-Aufrufe in nativen Code ausführen, der spezielle Anweisungen für CAS enthält
Lesen Sie hier mehr über CAS http://en.wikipedia.org/wiki/Compare-and-swap
Die sun.misc.Unsafe-Funktionalität der Host-VM kann verwendet werden, um nicht initialisierte Objekte zuzuweisen und den Konstruktoraufruf dann wie jeden anderen Methodenaufruf zu interpretieren.
Man kann die Daten von der nativen Adresse aus verfolgen. Es ist möglich, die Speicheradresse eines Objekts mit der Klasse java.lang.Unsafe abzurufen und seine Felder direkt über unsichere get / put-Methoden zu bearbeiten!
Kompilieren Sie Zeitoptimierungen für JVM. Hochleistungs-VM mit "Magie", die Operationen auf niedriger Ebene erfordert. Beispiel: http://en.wikipedia.org/wiki/Jikes_RVM
Zuweisen von Speicher, sun.misc.Unsafe.allocateMemory zB: - Der DirectByteBuffer-Konstruktor ruft ihn intern auf, wenn ByteBuffer.allocateDirect aufgerufen wird
Verfolgen des Aufrufstapels und Wiedergeben mit Werten, die von sun.misc.Unsafe instanziiert wurden, nützlich für die Instrumentierung
Mit sun.misc.Unsafe.arrayBaseOffset und arrayIndexScale können Arraylets entwickelt werden, eine Technik zum effizienten Aufteilen großer Arrays in kleinere Objekte, um die Echtzeitkosten für Scan-, Aktualisierungs- oder Verschiebungsvorgänge an großen Objekten zu begrenzen
http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java
Mehr zu Referenzen hier - http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html
quelle
Allein durch das Ausführen einer Suche in einer Codesuchmaschine erhalte ich die folgenden Beispiele:
Es gibt viele andere Beispiele, folgen Sie einfach dem obigen Link ...
quelle
Interessanterweise hatte ich noch nie von dieser Klasse gehört (was wahrscheinlich wirklich gut ist).
Eine Sache, die mir in den Sinn kommt, ist die Verwendung von Unsafe # setMemory , um Puffer auf Null zu setzen, die an einem Punkt vertrauliche Informationen enthielten (Passwörter, Schlüssel, ...). Sie könnten dies sogar für Felder mit "unveränderlichen" Objekten tun (andererseits könnte auch hier eine einfache alte Reflexion den Trick machen). Ich bin allerdings kein Sicherheitsexperte, also nimm das mit einem Körnchen Salz.
quelle
I'd never even heard of this class
... Ich habe dir so oft davon erzählt! Seufzer + :(park()
Dokumentation: "Blockiere den aktuellen Thread und kehre zurück, wenn ein Ausgleichs-Unpark auftritt oder ein Ausgleichs-Unpark bereits aufgetreten ist oder der Thread unterbrochen ist oder, wenn nicht absolut und die Zeit nicht Null ist, der gegebene Zeit Nanosekunden sind abgelaufen, oder wenn absolut, die gegebene Frist in Millisekunden seit dem Ende der Epoche oder falsch (dh ohne "Grund" zurückzukehren) ". Fast so gut wie "Speicher wird freigegeben, wenn das Programm beendet wird, oder in zufälligen Intervallen, je nachdem, was zuerst eintritt".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. Speichermanipulationsfunktionen werden über DirectByteBuffer-Synchronisierungsanweisungen (Parken, Entparken) verfügbar gemacht, die über den AbstractQueuedSynchronizer verfügbar gemacht werden, der wiederum von Lock-Implementierungen verwendet wird.
quelle
LockSupport
nicht durch AQS ausgesetzt (letzteres ist eher eine Schleuse als Park / Unpark)Unsafe.throwException - Ermöglicht das Auslösen einer aktivierten Ausnahme, ohne sie 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. Der Benutzer kann angeben, welche Ausnahme in einem speziellen Fall von der Implementierung ausgelöst wird, indem er die Ausnahme in der Benutzeroberfläche deklariert. Dann ist dies der einzige Weg, den ich kenne, um eine aktivierte Ausnahme in der dynamischen Implementierung der Schnittstelle auszulösen.
quelle
Thread.stop(Throwable)
ohne unsichere zu benötigen, im gleichen Thread können Sie sowieso alles werfen (es gibt keine Kompilierungsprüfung)UnsupportedOperationException
Java 8 einen in den aktuellen Thread. Die Version ohne Argumente, die ausgelöst wird,ThreadDeath
funktioniert jedoch weiterhin.Eine Verwendung davon ist in
java.util.concurrent.atomic
Klassen:quelle
Für eine effiziente Speicherkopie (schneller zu kopieren als System.arraycopy (), zumindest für kurze Blöcke); wie von Java LZF- und Snappy- Codecs verwendet. Sie verwenden 'getLong' und 'putLong', die schneller sind als das byteweise Kopieren. Besonders effizient beim Kopieren von 16/32/64-Byte-Blöcken.
quelle
getLong/putLong
(und Sie müssen auch die Adresse berechnen)getLong
/ verwendeputLong
: Idealerweise würde ich es derSystem.arraycopy()
Einfachheit halber und allem vorziehen ; Die tatsächlichen Tests zeigten jedoch etwas anderes für Fälle, die ich getestet habe.Ich habe kürzlich an der Neuimplementierung der JVM gearbeitet und festgestellt, dass eine überraschende Anzahl von Klassen in Bezug auf implementiert ist
Unsafe
. Die Klasse wurde hauptsächlich für Java-Bibliotheksimplementierer entwickelt und enthält Funktionen, die grundsätzlich unsicher sind, aber zum Erstellen 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. Es ist nicht für die Verwendung durch normale Java-Programmierer vorgesehen. Es ist nicht dokumentiert, implementierungsspezifisch und von Natur aus unsicher (daher der Name!). Darüber hinaus denke ich, dass derSecurityManager
Zugang in fast allen Fällen nicht erlaubt ist.Kurz gesagt, es besteht hauptsächlich darin, Bibliotheksimplementierern den Zugriff auf den zugrunde liegenden Computer zu ermöglichen, ohne jede Methode in bestimmten Klassen wie
AtomicInteger
native deklarieren zu müssen . Sie sollten es in der routinemäßigen Java-Programmierung nicht verwenden oder sich darum kümmern müssen, da der springende Punkt darin besteht, den Rest der Bibliotheken so schnell zu machen, dass Sie keinen solchen Zugriff benötigen.quelle
Unsafe.class.getDeclaredField("theUnsafe")
mit.setAccessible(true)
und dann.get(null)
auchVerwenden Sie es, um effizient auf große Speichermengen zuzugreifen und diese zuzuweisen, z. B. in Ihrer eigenen Voxel-Engine! (dh Spiel im Minecraft-Stil.)
Nach meiner Erfahrung ist die JVM oft nicht in der Lage, die Überprüfung von Grenzen an den Stellen zu beseitigen, an denen Sie sie wirklich benötigen. Wenn Sie beispielsweise über ein großes Array iterieren, der tatsächliche Speicherzugriff jedoch unter einem nicht virtuellen * Methodenaufruf in der Schleife versteckt ist, führt die JVM möglicherweise weiterhin eine Überprüfung der Grenzen bei jedem Arrayzugriff durch und nicht nur einmal zuvor die Schleife. Für potenziell große Leistungssteigerungen können Sie daher die Überprüfung der JVM-Grenzen innerhalb der Schleife mithilfe einer Methode eliminieren, bei der sun.misc.Unsafe verwendet wird, um direkt auf den Speicher zuzugreifen, und sicherstellen, dass Sie die Grenzen an den richtigen Stellen überprüfen. (Sie sind Gonna Grenzen überprüfen auf einer bestimmten Ebene, nicht wahr?)
* Mit nicht virtuell meine ich, dass die JVM nicht dynamisch auflösen muss, was auch immer Ihre spezielle Methode ist, da Sie korrekt garantiert haben, dass Klasse / Methode / Instanz eine Kombination aus statisch / endgültig / was-haben-Sie sind.
Für meine selbstgebaute Voxel-Engine führte dies zu einem dramatischen Leistungsgewinn während der Chunk-Generierung und -Serialisierung (an Orten, an denen ich das gesamte Array gleichzeitig las / schrieb). Die Ergebnisse können variieren, aber wenn ein Mangel an Grenzbeseitigung Ihr Problem ist, wird dies das Problem beheben.
Hierbei gibt es einige potenziell schwerwiegende Probleme: Insbesondere wenn Sie Clients Ihrer Schnittstelle die Möglichkeit bieten, auf den Speicher zuzugreifen, ohne die Grenzen zu überprüfen, werden sie ihn wahrscheinlich missbrauchen. (Vergessen Sie nicht, dass Hacker auch Clients Ihrer Schnittstelle sein können ... insbesondere im Fall einer in Java geschriebenen Voxel-Engine.) Daher sollten Sie Ihre Schnittstelle entweder so gestalten, dass der Speicherzugriff nicht missbraucht werden kann, oder Sie sollten sehr vorsichtig sein , Benutzerdaten zu validieren , bevor es überhaupt kann, je mit gefährlicher Schnittstelle mische. Angesichts der katastrophalen Dinge, die ein Hacker mit ungeprüftem Speicherzugriff tun kann, ist es wahrscheinlich am besten, beide Ansätze zu wählen.
quelle
Off-Heap-Sammlungen können nützlich sein, um große Speichermengen zuzuweisen und die Zuweisung unmittelbar nach der Verwendung ohne GC-Interferenz aufzuheben. Ich habe eine Bibliothek für die Arbeit mit Off-Heap-Arrays / Listen geschrieben, die auf basieren
sun.misc.Unsafe
.quelle
Wir haben riesige Sammlungen wie Arrays, HashMaps, TreeMaps mit Unsafe implementiert.
Um die Fragmentierung zu vermeiden / zu minimieren, haben wir den Speicherzuweiser mithilfe der Konzepte von dlmalloc over unsicher implementiert .
Dies hat uns geholfen, die Leistung bei gleichzeitiger Verwendung zu steigern.
quelle
Unsafe.park()
undUnsafe.unpark()
für den Aufbau von benutzerdefinierten Parallelitätskontrollstrukturen und kooperativen Planungsmechanismen.quelle
java.util.concurrent.locks.LockSupport
Ich habe es selbst nicht verwendet, aber ich nehme an, wenn Sie eine Variable haben, die nur gelegentlich von mehr als einem Thread gelesen wird (damit Sie sie nicht wirklich flüchtig machen möchten), können Sie sie verwenden,
putObjectVolatile
wenn Sie sie in den Hauptthread und schreibenreadObjectVolatile
beim Ausführen der seltenen Lesevorgänge aus anderen Threads.quelle
Sie benötigen es, wenn Sie die Funktionen einer der Klassen ersetzen müssen, 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. B. eine derzeit nicht unterstützte.
Ich habe es irgendwann für all dies benutzt.
quelle
Ein Beispiel für seine Verwendung ist die Zufallsmethode, die die unsichere Methode zum Ändern des Startwerts aufruft .
Diese Seite hat auch einige Verwendungszwecke .
quelle
Das Objekt scheint die Verfügbarkeit zu sein, um auf einer niedrigeren Ebene zu arbeiten, als es Java-Code normalerweise zulässt. Wenn Sie eine Anwendung auf hoher Ebene codieren, abstrahiert die JVM die Speicherbehandlung und andere Vorgänge von der Codeebene weg, sodass die Programmierung einfacher ist. Durch die Verwendung der unsicheren Bibliothek führen Sie effektiv Operationen auf niedriger Ebene aus, die normalerweise für Sie ausgeführt werden.
Wie woliveirajr sagte, verwendet "random ()" Unsafe, um zu setzen, genauso wie viele andere Operationen die in Unsafe enthaltene Funktion allocateMemory () verwenden.
Als Programmierer könnten Sie wahrscheinlich davonkommen, diese Bibliothek nie zu benötigen, aber eine strikte Kontrolle über Elemente auf niedriger Ebene ist praktisch (aus diesem Grund gibt es in wichtigen Produkten immer noch Assembly- und (in geringerem Maße) C-Code).
quelle