Saya menemukan paket sun.misc.Unsafe hari yang lalu dan kagum pada apa yang bisa dilakukan.
Tentu saja, kelas tidak berdokumen, tetapi saya bertanya-tanya apakah ada alasan yang bagus untuk menggunakannya. Skenario apa yang mungkin muncul di mana Anda perlu menggunakannya? Bagaimana itu bisa digunakan dalam skenario dunia nyata?
Lebih jauh, jika Anda benar- benar membutuhkannya, apakah itu tidak mengindikasikan bahwa ada sesuatu yang salah dengan desain Anda?
Mengapa Java bahkan memasukkan kelas ini?
Jawaban:
contoh
VM "intrinsifikasi." yaitu CAS (Compare-And-Swap) yang digunakan dalam Lock-Free Hash Tables misalnya: sun.misc.Unsafe.compareAndSwapInt dapat membuat panggilan JNI nyata ke dalam kode asli yang berisi instruksi khusus untuk CAS
baca lebih lanjut tentang CAS di sini http://en.wikipedia.org/wiki/Compare-and-swap
Fungsionalitas sun.misc.Unsafe dari host VM dapat digunakan untuk mengalokasikan objek yang tidak diinisialisasi dan kemudian menginterpretasikan permintaan konstruktor sebagai panggilan metode lainnya.
Seseorang dapat melacak data dari alamat asli. Dimungkinkan untuk mengambil alamat memori objek menggunakan kelas java.lang.Unsafe, dan beroperasi pada bidangnya langsung melalui metode get / put yang tidak aman!
Kompilasi optimasi waktu untuk JVM. VM kinerja tinggi yang menggunakan "sihir", membutuhkan operasi tingkat rendah. misalnya: http://en.wikipedia.org/wiki/Jikes_RVM
Mengalokasikan memori, sun.misc.Unsafe.allocateMemory misalnya: - DirectByteBuffer constructor secara internal menyebutnya ketika ByteBuffer.allocateDirect dipanggil
Menelusuri tumpukan panggilan dan memutar ulang dengan nilai yang digunakan oleh sun.misc.Unsafe, berguna untuk instrumentasi
sun.misc.Unsafe.arrayBaseOffset dan arrayIndexScale dapat digunakan untuk mengembangkan arraylets, sebuah teknik untuk memecah array besar menjadi objek yang lebih kecil untuk membatasi biaya real-time pemindaian, memperbarui atau memindahkan operasi pada objek besar
http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java
lebih lanjut tentang referensi di sini - http://bytescrolls.blogspot.com/2011/04/tarik
sumber
Hanya dari menjalankan pencarian di beberapa mesin pencari kode saya mendapatkan contoh-contoh berikut:
Ada banyak contoh lain, cukup ikuti tautan di atas ...
sumber
Menarik, saya bahkan belum pernah mendengar tentang kelas ini (yang mungkin merupakan hal yang baik, sungguh).
Satu hal yang terlintas dalam pikiran adalah menggunakan Unsafe # setMemory untuk memusatkan buffer yang berisi informasi sensitif pada satu titik (kata sandi, kunci, ...). Anda bahkan dapat melakukan ini pada bidang objek "yang tidak dapat diubah" (sekali lagi saya kira pantulan lama yang polos dapat melakukan trik di sini juga). Saya bukan ahli keamanan jadi bawa ini dengan sebutir garam.
sumber
I'd never even heard of this class
... Aku sudah berkali-kali memberitahumu tentang itu! sigh + :(park()
dokumentasi mereka : "Blokir utas saat ini, kembali ketika balancing unpark terjadi, atau balancing unpark telah terjadi, atau utas terputus, atau, jika tidak absolut dan waktu tidak nol, waktu nanodetik telah berlalu, atau jika absolut, batas waktu yang diberikan dalam milidetik sejak Epoch telah berlalu, atau palsu (yaitu, kembali tanpa 'alasan') ". Hampir sebagus "memori dibebaskan ketika program keluar, atau, pada interval acak, mana yang lebih dulu".Berdasarkan analisis yang sangat singkat dari pustaka Java 1.6.12 menggunakan eclipse untuk pelacakan referensi, tampaknya seolah-olah setiap fungsi yang berguna
Unsafe
terpapar dengan cara yang bermanfaat.Operasi CAS terpapar melalui kelas Atom *. Fungsi manipulasi memori diekspos melalui instruksi DirectByteBuffer Sync (park, unpark) diekspos melalui AbstractQueuedSynchronizer yang pada gilirannya digunakan oleh implementasi Lock.
sumber
LockSupport
bukan AQS (yang terakhir lebih merupakan alat kunci dari pada park / unpark)Unsafe.throwException - memungkinkan untuk melempar pengecualian yang diperiksa tanpa mendeklarasikannya.
Ini berguna dalam beberapa kasus di mana Anda berurusan dengan refleksi atau AOP.
Asumsikan Anda Membangun proxy generik untuk Antarmuka yang ditentukan pengguna. Dan pengguna dapat menentukan pengecualian mana yang dilemparkan oleh implementasi dalam kasus khusus hanya dengan menyatakan pengecualian di antarmuka. Maka ini adalah satu-satunya cara saya tahu, untuk meningkatkan pengecualian diperiksa dalam Implementasi Antarmuka Dinamis.
sumber
Thread.stop(Throwable)
tanpa perlu tidak aman, di utas yang sama Anda dapat membuang apa saja (tidak ada pemeriksaan kompilasi)UnsupportedOperationException
di utas saat ini pada Java 8. Namun, versi tanpa argumen yang melemparThreadDeath
masih berfungsi.Salah satu penggunaannya adalah di
java.util.concurrent.atomic
kelas:sumber
Untuk penyalinan memori yang efisien (lebih cepat untuk menyalin daripada System.arraycopy () setidaknya untuk blok pendek); seperti yang digunakan oleh Java LZF dan Snappy codec. Mereka menggunakan 'getLong' dan 'putLong', yang lebih cepat daripada melakukan salinan byte-by-byte; sangat efisien saat menyalin hal-hal seperti blok 16/32/64 byte.
sumber
getLong/putLong
(dan Anda harus menghitung alamatnya juga)getLong
/putLong
: idealnya saya lebih sukaSystem.arraycopy()
untuk kesederhanaan dan semuanya; tetapi pengujian aktual menunjukkan sebaliknya untuk kasus yang telah saya uji.Saya baru-baru ini sedang mengerjakan mengimplementasikan JVM dan menemukan bahwa sejumlah kelas yang mengejutkan diimplementasikan dalam hal
Unsafe
. Kelas ini sebagian besar dirancang untuk pelaksana perpustakaan Java dan berisi fitur yang pada dasarnya tidak aman tetapi diperlukan untuk membangun primitif cepat. Misalnya, ada metode untuk mendapatkan dan menulis offset bidang mentah, menggunakan sinkronisasi tingkat perangkat keras, mengalokasikan dan membebaskan memori, dll. Ini tidak dimaksudkan untuk digunakan oleh programmer Java biasa; itu tidak berdokumen, khusus implementasi, dan secara inheren tidak aman (karenanya namanya!). Selain itu, saya pikir bahwaSecurityManager
akan melarang akses ke sana di hampir semua kasus.Singkatnya, ini terutama ada untuk memungkinkan pelaksana perpustakaan akses ke mesin yang mendasarinya tanpa harus mendeklarasikan setiap metode di kelas tertentu seperti
AtomicInteger
asli. Anda tidak perlu menggunakan atau mengkhawatirkannya dalam pemrograman Java rutin, karena intinya adalah membuat seluruh perpustakaan cukup cepat sehingga Anda tidak memerlukan akses semacam itu.sumber
Unsafe.class.getDeclaredField("theUnsafe")
dengan.setAccessible(true)
dan kemudian.get(null)
akan mendapatkannya jugaGunakan untuk mengakses dan mengalokasikan sejumlah besar memori secara efisien, seperti di mesin voxel Anda sendiri! (Yaitu permainan bergaya Minecraft.)
Dalam pengalaman saya, JVM sering tidak dapat menghilangkan batas memeriksa di tempat Anda benar-benar membutuhkannya. Misalnya, jika Anda mengulangi array yang besar, tetapi akses memori yang sebenarnya tersimpan di bawah panggilan metode non-virtual * dalam loop, JVM mungkin masih melakukan pemeriksaan batas dengan setiap akses array, daripada hanya sekali sebelum putaran. Dengan demikian, untuk keuntungan kinerja yang berpotensi besar, Anda dapat menghilangkan pemeriksaan batas JVM di dalam loop melalui metode yang menggunakan sun.misc. Tidak aman untuk mengakses memori secara langsung, memastikan untuk melakukan batasan-memeriksa diri Anda di tempat yang benar. (Anda yang akan batas-batas memeriksa pada tingkat tertentu, kan?)
* oleh non-virtual, maksud saya JVM tidak harus secara dinamis menyelesaikan apa pun metode khusus Anda, karena Anda telah dengan benar menjamin bahwa kelas / metode / instance adalah beberapa kombinasi dari static / final / what-have-you.
Untuk mesin voxel rumahan saya, ini menghasilkan peningkatan kinerja yang dramatis selama generasi chunk dan serialisasi (sekarang tempat di mana saya membaca / menulis ke seluruh array sekaligus). Hasil mungkin bervariasi, tetapi jika kurangnya batasan-eliminasi adalah masalah Anda, maka ini akan memperbaikinya.
Ada beberapa masalah yang berpotensi besar dengan ini: khususnya, ketika Anda memberikan kemampuan untuk mengakses memori tanpa batas memeriksa ke klien dari antarmuka Anda, mereka mungkin akan menyalahgunakannya. (Jangan lupa bahwa peretas juga bisa menjadi klien dari antarmuka Anda ... terutama dalam kasus mesin voxel yang ditulis dalam Java.) Jadi, Anda harus mendesain antarmuka Anda sedemikian rupa sehingga akses memori tidak dapat disalahgunakan, atau Anda harus sangat berhati-hati untuk memvalidasi user-data sebelum itu pernah dapat, pernah berbaur dengan antarmuka yang berbahaya Anda. Mempertimbangkan hal-hal bencana yang dapat dilakukan oleh seorang hacker dengan akses memori yang tidak diperiksa, mungkin lebih baik mengambil kedua pendekatan tersebut.
sumber
Koleksi di luar tumpukan mungkin berguna untuk mengalokasikan sejumlah besar memori dan membatalkan alokasi segera setelah digunakan tanpa gangguan GC. Saya menulis perpustakaan untuk bekerja dengan susunan / daftar off-heap berdasarkan
sun.misc.Unsafe
.sumber
Kami telah mengimplementasikan koleksi besar seperti Array, HashMaps, TreeMaps menggunakan Tidak Aman.
Dan untuk menghindari / meminimalkan fragmentasi, kami menerapkan pengalokasi memori menggunakan konsep dlmalloc lebih tidak aman.
Ini membantu kami untuk mendapatkan kinerja dalam konkurensi.
sumber
Unsafe.park()
danUnsafe.unpark()
untuk konstruksi struktur kontrol konkurensi khusus dan mekanisme penjadwalan kerja sama.sumber
java.util.concurrent.locks.LockSupport
Belum pernah menggunakannya sendiri, tapi saya kira jika Anda memiliki variabel yang hanya sesekali dibaca oleh lebih dari satu utas (sehingga Anda tidak benar-benar ingin membuatnya mudah berubah) Anda dapat menggunakannya
putObjectVolatile
saat menulisnya di utas utama danreadObjectVolatile
ketika melakukan membaca langka dari utas lainnya.sumber
Anda memerlukannya jika Anda perlu mengganti fungsionalitas yang disediakan oleh salah satu kelas yang menggunakannya saat ini.
Ini bisa berupa kustomisasi / deserialisasi yang lebih cepat / lebih ringkas, versi lebih cepat / lebih besar dari buffer / resizable ByteBuffer, atau menambahkan variabel atom misalnya yang tidak didukung saat ini.
Saya telah menggunakannya untuk semua ini pada suatu waktu.
sumber
Salah satu contoh penggunaannya adalah metode acak, yang memanggil yang tidak aman untuk mengubah seed .
Situs ini juga memiliki beberapa kegunaan .
sumber
Objek tampaknya menjadi ketersediaan untuk bekerja di tingkat yang lebih rendah dari apa yang biasanya diizinkan oleh kode Java. Jika Anda sedang mengkode aplikasi tingkat tinggi maka JVM akan mengabstraksi penanganan memori dan operasi lainnya dari tingkat kode sehingga lebih mudah diprogram. Dengan menggunakan pustaka Tidak Aman, Anda secara efektif menyelesaikan operasi tingkat rendah yang biasanya dilakukan untuk Anda.
Seperti woliveirajr menyatakan "random ()" menggunakan Unsafe untuk seed seperti halnya banyak operasi lain akan menggunakan fungsi alokasiateMemory () yang termasuk dalam Unsafe.
Sebagai seorang programmer Anda mungkin bisa lolos dengan tidak perlu perpustakaan ini tetapi memiliki kontrol ketat atas elemen-elemen tingkat rendah memang berguna (itu sebabnya masih ada Majelis dan (pada tingkat lebih rendah) kode C melayang-layang di dalam produk-produk utama)
sumber