Я наткнулся на пакет sun.misc.Unsafe на днях и был поражен тем, что он может сделать.
Конечно, класс недокументирован, но мне было интересно, была ли когда-нибудь веская причина использовать его. Какие сценарии могут возникнуть, когда вам нужно будет использовать его? Как это может быть использовано в реальном сценарии?
Кроме того, если вам это нужно, не означает ли это, что что-то не так с вашим дизайном?
Почему Java даже включает этот класс?
Ответы:
Примеры
ВМ "Интрификация". т.е. CAS (Compare-And-Swap), используемый в хэш-таблицах без блокировок, например: sun.misc.Unsafe.compareAndSwapInt он может делать реальные вызовы JNI в собственный код, который содержит специальные инструкции для CAS
Узнайте больше о CAS здесь http://en.wikipedia.org/wiki/Compare-and-swap
Функциональность sun.misc.Unsafe виртуальной машины хоста может использоваться для выделения неинициализированных объектов, а затем интерпретировать вызов конструктора как любой другой вызов метода.
Можно отслеживать данные по собственному адресу. Можно получить адрес памяти объекта с помощью класса java.lang.Unsafe и работать с его полями напрямую через небезопасные методы get / put!
Оптимизация времени компиляции для JVM. Высокая производительность ВМ с использованием «магии», требующей низкоуровневых операций. например: http://en.wikipedia.org/wiki/Jikes_RVM
Выделение памяти, sun.misc.Unsafe.allocateMemory, например: - конструктор DirectByteBuffer внутренне вызывает его, когда вызывается ByteBuffer.allocateDirect
Трассировка стека вызовов и воспроизведение со значениями, созданными экземпляром sun.misc.Unsafe, полезным для инструментария
sun.misc.Unsafe.arrayBaseOffset и arrayIndexScale могут быть использованы для разработки массивов, техники эффективного разбиения больших массивов на более мелкие объекты, чтобы ограничить стоимость сканирования, обновления или перемещения больших объектов в режиме реального времени.
http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java
больше на ссылках здесь - http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html
источник
Просто запустив поиск в некоторой поисковой системе кода, я получаю следующие примеры:
Есть много других примеров, просто перейдите по ссылке выше ...
источник
Интересно, что я никогда не слышал об этом классе (что, наверное, хорошо, правда).
Одна вещь, которая приходит на ум, - это использование Unsafe # setMemory для обнуления буферов, которые содержали конфиденциальную информацию в одном месте (пароли, ключи, ...). Вы могли бы даже сделать это с полями «неизменяемых» объектов (опять же, я полагаю, что и здесь может помочь простое старое отражение). Я не эксперт по безопасности, так что возьмите это с крошкой соли.
источник
I'd never even heard of this class
... Я говорил вам об этом много раз! вздох + :(park()
документация: «Заблокировать текущий поток, возвращающийся, когда происходит разблокировка балансировки, или уже произошла разблокировка балансировки, или поток прерывается, или, если не абсолютное значение, а время не равно нулю, заданное время истекло наносекунды или, если оно абсолютное, заданный крайний срок в миллисекундах с тех пор, как прошла Эпоха, или с лихвой (т. е. возвращение без «причины») ». Почти так же хорошо, как «память освобождается при выходе из программы или через произвольные интервалы, в зависимости от того, что наступит раньше».Основываясь на очень кратком анализе библиотеки Java 1.6.12 с использованием eclipse для отслеживания ссылок, кажется, что каждая полезная функциональность
Unsafe
раскрывается полезными способами.Операции CAS предоставляются через классы Atomic *. Функции манипулирования памятью предоставляются через инструкции DirectByteBuffer Sync (park, unpark) и через AbstractQueuedSynchronizer, который, в свою очередь, используется реализациями Lock.
источник
LockSupport
не через AQS (последний является скорее замком, чем парковка / unpark)Unsafe.throwException - позволяет бросить проверенное исключение, не объявляя их.
Это полезно в некоторых случаях, когда вы имеете дело с рефлексией или АОП.
Предположим, вы создали универсальный прокси для пользовательского интерфейса. И пользователь может указать, какое исключение выдается имплементацией в особом случае, просто объявив исключение в интерфейсе. Тогда это единственный способ, которым я знаю, - вызвать проверенное исключение в динамической реализации интерфейса.
источник
Thread.stop(Throwable)
без необходимости в небезопасных, в том же потоке вы можете бросить что угодно в любом случае (нет проверки компиляции)UnsupportedOperationException
текущий поток начиная с Java 8. Однако версия без аргументов, которая выдает,ThreadDeath
все еще работает.Одно использование этого в
java.util.concurrent.atomic
классах:источник
Для эффективного копирования памяти (быстрее копировать, чем System.arraycopy () для коротких блоков по крайней мере); как используется Java LZF и кодеками Snappy . Они используют 'getLong' и 'putLong', которые работают быстрее, чем делают побайтные копии; особенно эффективно при копировании таких вещей, как блоки 16/32/64 байта.
источник
getLong/putLong
(и вы должны также рассчитать адрес)getLong
/putLong
: в идеале я бы предпочелSystem.arraycopy()
для простоты и все; но фактическое тестирование показало обратное для случаев, которые я проверял.Недавно я работал над реализацией JVM и обнаружил, что в плане реализовано удивительное количество классов
Unsafe
. Этот класс в основном предназначен для разработчиков библиотек Java и содержит функции, которые в основном небезопасны, но необходимы для создания быстрых примитивов. Например, существуют методы для получения и записи необработанных смещений полей, использующие синхронизацию на уровне оборудования, выделение и освобождение памяти и т. Д. Он не предназначен для использования обычными программистами Java; он недокументирован, специфичен для реализации и небезопасен (отсюда и название!). Более того, я считаю, чтоSecurityManager
доступ к нему будет закрыт практически во всех случаях.Короче говоря, он в основном существует, чтобы позволить разработчикам библиотек доступ к базовому компьютеру без необходимости объявлять каждый метод в определенных классах, как
AtomicInteger
native. Вам не нужно использовать или беспокоиться об этом в обычном программировании на Java, поскольку весь смысл в том, чтобы сделать остальные библиотеки достаточно быстрыми, чтобы вам не требовался такой доступ.источник
Unsafe.class.getDeclaredField("theUnsafe")
с.setAccessible(true)
и затем.get(null)
получите его тожеИспользуйте его для эффективного доступа к большим объемам памяти, например, в вашем собственном воксельном движке! (т.е. игра в стиле Minecraft.)
По моему опыту, JVM часто не может устранить проверку границ там, где она действительно вам нужна. Например, если вы выполняете итерации по большому массиву, но фактический доступ к памяти скрывается за вызовом невиртуального * метода в цикле, JVM может выполнять проверку границ при каждом доступе к массиву, а не один раз перед петля. Таким образом, для потенциально большого прироста производительности вы можете исключить проверку границ JVM внутри цикла с помощью метода, использующего sun.misc.Unsafe для прямого доступа к памяти, обязательно проверяя границы в нужных местах. (Вы находитесь Gonna границы проверить на каком - то уровне, не так ли?)
* не виртуальным, я имею в виду, что JVM не должна динамически разрешать какой бы то ни было ваш конкретный метод, потому что вы правильно гарантировали, что класс / метод / экземпляр - это некоторая комбинация static / final / what-have-you.
Для моего собственного воксельного движка это привело к значительному увеличению производительности во время генерации фрагментов и сериализации (iow места, где я читал / записывал весь массив одновременно). Результаты могут отличаться, но если ваша проблема связана с отсутствием устранения границ, это решит проблему.
В этом есть некоторые потенциально серьезные проблемы: в частности, когда вы предоставляете возможность доступа к памяти без проверки границ клиентам вашего интерфейса, они, вероятно, будут злоупотреблять ею. (Не забывайте, что хакеры также могут быть клиентами вашего интерфейса ... особенно в случае воксельного движка, написанного на Java.) Таким образом, вы должны либо спроектировать свой интерфейс таким образом, чтобы доступ к памяти не мог быть нарушен, либо Вы должны быть чрезвычайно осторожны при проверке пользовательских данных, прежде чем они когда- либо смогут смешаться с вашим опасным интерфейсом. Учитывая катастрофические вещи, которые хакер может сделать с неконтролируемым доступом к памяти, вероятно, лучше всего использовать оба подхода.
источник
Коллекции вне кучи могут быть полезны для выделения огромных объемов памяти и освобождения ее сразу после использования без вмешательства ГХ. Я написал библиотеку для работы с массивами / списками вне кучи на основе
sun.misc.Unsafe
.источник
Мы реализовали огромные коллекции, такие как Arrays, HashMaps, TreeMaps, используя Unsafe.
И чтобы избежать / минимизировать фрагментацию, мы реализовали распределитель памяти, используя понятия dlmalloc вместо unsafe.
Это помогло нам получить производительность в параллельном режиме.
источник
Unsafe.park()
иUnsafe.unpark()
для создания пользовательских структур управления параллелизмом и механизмов совместного планирования.источник
java.util.concurrent.locks.LockSupport
Я не использовал его сам, но я полагаю, что если у вас есть переменная, которая только изредка читается более чем одним потоком (так что вы не хотите, чтобы она была энергозависимой), вы можете использовать ее
putObjectVolatile
при записи в основной поток иreadObjectVolatile
при выполнении редких чтений из других потоков.источник
Вам это нужно, если вам нужно заменить функциональность, предоставляемую одним из классов, который использует его в настоящее время.
Это может быть пользовательская / более быстрая / более компактная сериализация / десериализация, более быстрая / более крупная буферная версия / версия с изменяемыми размерами ByteBuffer или добавление атомарной переменной, например, не поддерживаемой в настоящее время.
Я использовал это для всего этого в какое-то время.
источник
Одним из примеров его использования является случайный метод, который вызывает небезопасное изменение начального числа .
Этот сайт также имеет некоторые возможности его использования .
источник
Похоже, что объект доступен для работы на более низком уровне, чем обычно позволяет код Java. Если вы кодируете приложение высокого уровня, то JVM абстрагирует обработку памяти и другие операции от уровня кода, что облегчает программирование. Используя библиотеку Unsafe, вы эффективно выполняете низкоуровневые операции, которые обычно выполняются за вас.
Как сказал woliveirajr, «random ()» использует Unsafe для заполнения так же, как многие другие операции будут использовать функцию allocateMemory (), включенную в Unsafe.
Как программисту вы, вероятно, могли бы сойти с рук, никогда не нуждаясь в этой библиотеке, но иметь строгий контроль над низкоуровневыми элементами действительно полезно (вот почему все еще существует ассемблер и (в меньшей степени) код на C, распространяющийся в основных продуктах)
источник