Warum existiert sun.misc.Unsafe und wie kann es in der realen Welt verwendet werden? [geschlossen]

255

Ich habe das Paket sun.misc.Unsafe neulich gesehen und war erstaunt, was es tun könnte.

Natürlich ist die Klasse undokumentiert, aber ich habe mich gefragt, ob es jemals einen guten Grund gab, sie zu benutzen. Welche Szenarien könnten entstehen, wo Sie sie verwenden müssten? Wie könnte es in einem realen Szenario verwendet werden?

Wenn Sie tun brauchen, bedeutet das nicht, dass etwas mit Ihrem Design nicht stimmt?

Warum schließt Java diese Klasse sogar ein?

    
pdeva 06.04.2011, 23:38
quelle

16 Antworten

152

Beispiele

  1. VM "intrinsification" dh CAS (Compare-And-Swap), das in Lock-Free Hash Tables verwendet wird zB: sun.misc.Unsafe.compareAndSwapInt es kann echte JNI-Aufrufe in nativen Code machen, der spezielle Anweisungen für CAS enthält

    Lesen Sie mehr über CAS hier Ссылка

  2. Die Funktion sun.misc.Unsafe der Host-VM kann verwendet werden, um nicht initialisierte Objekte zuzuweisen und den Aufruf des Konstruktors dann wie jeden anderen Methodenaufruf zu interpretieren.

  3. Man kann die Daten von der nativen Adresse aus verfolgen. Es ist möglich, ein Speicheradresse des Objekts, die die java.lang.Unsafe-Klasse verwendet, und bearbeiten ihre Felder direkt über unsichere get / put-Methoden!

  4. Kompilieren Sie Zeitoptimierungen für JVM. Hohe Leistung VM mit "Magie", erfordert Low-Level-Operationen. zB: Ссылка

  5. Zuweisung von Speicher, sun.misc.Unsafe.allocateMemory zB: - Der DirectByteBuffer-Konstruktor ruft ihn intern auf, wenn ByteBuffer.allocateDirect aufgerufen wird

  6. Verfolgen des Aufruf-Stacks 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 verwendet werden, um Arraylets zu entwickeln, eine 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. Ссылка

mehr zu Referenzen hier - Ссылка

    
zudokod 13.04.2011 17:50
quelle
31

Nur, wenn Sie eine Suche in einigen Code-Suchmaschine bekomme ich die folgenden Beispiele:

  • Java Object Notation - verwenden Sie es für eine effizientere Array-Verarbeitung und zitieren Sie das Javadoc
  

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

  

/ ** Basisklasse für sun.misc.Unsafe-basierte FieldAccessors für statische       Felder. Die Beobachtung ist, dass es nur neun Arten gibt       Felder vom Standpunkt der Reflexion Code: die acht Primitive       Typen und Objekt. Verwenden der Klasse Nicht sicher statt generiert       Bytecodes spart Speicher und Ladezeit für die       dynamisch generierte FieldAccessors. * /

  • SpikeSource
  

/ *    FinalFields, die über den Draht gesendet werden .. wie das Objekt auf dem Remarshall und neu erstellen    Empfangsseite? Wir möchten den Konstruktor nicht aufrufen, da er Werte für    letzte Felder. Wir müssen das letzte Feld genau so erstellen, wie es auf der Senderseite war.    Die sun.misc.Unsafe macht das für uns.    * /

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

    
Asaf 09.04.2011 19:49
quelle
24

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

Eine Sache, die einem in den Sinn kommt, ist die Verwendung von Unsicher # setMemory , um Puffer aufzulösen, die an einem Punkt vertrauliche Informationen enthielten (Passwörter, Schlüssel, ...). Du könntest das sogar mit Feldern von "unveränderlichen" Objekten tun (dann nehme ich wieder an, dass eine einfache alte Reflexion auch hier den Trick leisten könnte). Ich bin kein Sicherheitsexperte, aber nehmen Sie das mit einem Körnchen Salz.

    
Mike Daniels 09.04.2011 18:56
quelle
21

Unsafe.throwException - ermöglicht das Übergeben der geprüften Ausnahme, ohne sie zu deklarieren.

Dies ist in einigen Fällen hilfreich, in denen Sie mit Reflexion oder AOP arbeiten.

Angenommen, Sie erstellen einen generischen Proxy für eine benutzerdefinierte Schnittstelle. Und der Benutzer kann in einem speziellen Fall angeben, welche Ausnahme von der Implementation ausgelöst wird, indem einfach die Ausnahme in der Schnittstelle deklariert wird. Dann ist dies die einzige Art, wie ich weiß, eine geprüfte Ausnahme in der dynamischen Implementierung der Schnittstelle zu erhöhen.

%Vor%     
Ralph 13.04.2011 11:20
quelle
21

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

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

    
Tim Bender 11.04.2011 21:22
quelle
9
  

Klasse unsicher

     

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

Eine Verwendung davon ist in java.util.concurrent.atomic classes:

Margus 09.04.2011 16:36
quelle
6

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

    
StaxMan 11.12.2011 04:41
quelle
5

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

Nach meiner Erfahrung ist die JVM oft nicht in der Lage, Begrenzungen zu eliminieren, die Sie wirklich brauchen. Wenn Sie beispielsweise über ein großes Array iterieren, der tatsächliche Speicherzugriff jedoch unter einem nicht virtuellen * Methodenaufruf in der Schleife verborgen ist, führt die JVM möglicherweise weiterhin eine Bereichsüberprüfung mit jedem Arrayzugriff durch, anstatt zuvor die Schleife. Für potentiell große Leistungssteigerungen können Sie JVM-Grenzen innerhalb der Schleife durch eine Methode eliminieren, die sun.misc.Unsafe verwendet, um direkt auf den Speicher zuzugreifen, wobei Sie sicherstellen müssen, dass Sie sich selbst an den richtigen Stellen überprüfen. (Sie werden Grenzen auf einer Ebene prüfen, richtig?)
* von nicht-virtuellen, ich meine, die JVM sollte nicht dynamisch lösen, was auch immer Ihre bestimmte Methode ist, weil Sie haben korrekt sichergestellt, dass Klasse / Methode / Instanz eine Kombination aus statisch / final / was-haben-Sie-haben.

Für meine selbst entwickelte Voxel-Engine führte dies zu einem dramatischen Leistungszuwachs bei der Chunk-Generierung und -Serialisierung (also Stellen, an denen ich das gesamte Array gleichzeitig gelesen / geschrieben hatte). Die Ergebnisse können variieren, aber wenn ein Mangel an Grenzen-Eliminierung Ihr Problem ist, wird dies es beheben.

Es gibt einige potentiell schwerwiegende Probleme: Insbesondere, wenn Sie die Möglichkeit bieten, auf den Speicher ohne Grenzen zu zugreifen, werden die Clients sie wahrscheinlich missbrauchen. (Vergessen Sie nicht, dass Hacker auch Clients Ihrer Schnittstelle sein können ... besonders im Fall einer Voxel-Engine, die in Java geschrieben ist.) Daher sollten Sie Ihre Schnittstelle entweder so gestalten, dass der Speicherzugriff nicht missbraucht werden kann, oder Sie sollten äußerst vorsichtig sein, um Benutzerdaten zu validieren, bevor sie jemals jemals mit Ihrer gefährlichen Schnittstelle in Verbindung gebracht werden können. Angesichts der katastrophalen Dinge, die ein Hacker mit unkontrolliertem Speicherzugriff tun kann, ist es wahrscheinlich am besten, beide Ansätze zu verfolgen.

    
Philip 02.01.2014 06:27
quelle
4

Ich habe kürzlich daran gearbeitet, die JVM neu zu implementieren und festgestellt, dass eine überraschende Anzahl von Klassen in 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 Primitive erforderlich sind. Zum Beispiel gibt es Methoden zum Abrufen und Schreiben von Raw-Field-Offsets, zum Verwenden von Hardware-Level-Synchronisation, zum Zuweisen und Freigeben von Speicher usw. Es ist nicht dazu gedacht, von normalen Java-Programmierern verwendet zu werden; Es ist undokumentiert, implementierungsspezifisch und von Natur aus unsicher (daher der Name!). Darüber hinaus glaube ich, dass% code% in fast allen Fällen keinen Zugriff darauf erlaubt.

Kurz gesagt besteht es hauptsächlich, um Bibliotheks-Implementierern Zugriff auf die zugrunde liegende Maschine zu gewähren, ohne jede Methode in bestimmten Klassen wie SecurityManager nativ deklarieren zu müssen. Sie sollten sich in der routinemäßigen Java-Programmierung nicht darum kümmern oder sich darum kümmern müssen, da es darum geht, den Rest der Bibliotheken so schnell zu machen, dass Sie diese Art des Zugriffs nicht benötigen würden.

    
templatetypedef 13.07.2011 16:01
quelle
4

Off-Heap-Auflistungen können nützlich sein, um große Speichermengen zuzuordnen und sie sofort nach der Verwendung ohne GC-Interferenz freizugeben. Ich habe eine Bibliothek geschrieben, um mit Off-Heap-Arrays / Listen zu arbeiten, die auf sun.misc.Unsafe basieren.

    
alexkasko 15.03.2013 19:41
quelle
3

Unsafe.park() und Unsafe.unpark() für die Konstruktion von benutzerdefinierten Parallelitätskontrollstrukturen und kooperativen Scheduling-Mechanismen.

    
andersoj 09.04.2011 19:22
quelle
3

Wir haben riesige Sammlungen wie Arrays, HashMaps, TreeMaps mit Unsafe implementiert. Um die Fragmentierung zu vermeiden / minimieren, haben wir den Speicherzuordner unter Verwendung der Konzepte von dlmalloc über unsichere.
Dies hat uns geholfen, die Leistung im Parallelbetrieb zu erreichen.

    
pradipmw 21.01.2014 04:47
quelle
1

Ich habe es nicht selbst benutzt, aber ich nehme an, wenn Sie eine Variable haben, die nur gelegentlich von mehr als einem Thread gelesen wird (Sie wollen es also nicht flüchtig machen), könnten Sie putObjectVolatile beim Schreiben verwenden es im Haupt-Thread und readObjectVolatile , wenn die seltenen liest von anderen Threads.

    
Matt Crinklaw-Vogt 07.04.2011 00:31
quelle
1

Ein Beispiel für seine Verwendung ist die Zufallsmethode, die ruft den unsicheren Benutzer auf, um den Seed zu ändern .

Diese Seite hat auch einige Anwendungen davon .

>     
woliveirajr 13.07.2011 15:44
quelle
0

Das Objekt scheint verfügbar zu sein, um auf einer niedrigeren Ebene zu arbeiten, als der Java-Code normalerweise zulässt. Wenn Sie eine High-Level-Anwendung codieren, abstrahiert die JVM die Speicherbehandlung und andere Operationen von der Codeebene, so dass sie einfacher zu programmieren ist. Indem Sie die unsichere Bibliothek verwenden, schließen Sie Operationen auf niedriger Ebene ab, die normalerweise für Sie erledigt werden.

Wie woliveirajr angegeben hat, verwendet "random ()" Unsafe zum Start, genauso wie viele andere Operationen die Funktion allocateMemory () verwenden, die in Unsafe enthalten ist.

Als Programmierer könnten Sie wahrscheinlich davonkommen, dass Sie diese Bibliothek nie brauchen, aber eine strenge Kontrolle über Low-Level-Elemente ist nützlich (deshalb gibt es immer noch Assembly und (in geringerem Maße) C-Code, der in wichtigen Produkten herumtreibt )

    
Grambot 13.07.2011 15:46
quelle
0

Sie benötigen es, wenn Sie die Funktionalität ersetzen müssen, die von einer der Klassen bereitgestellt wird, die sie derzeit verwenden.

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

Ich habe es für alle diese irgendwann verwendet.

    
Peter Lawrey 13.07.2011 16:42
quelle

Tags und Links