为什么sun.misc.Unsafe存在,如何在现实世界中使用?
有一天我遇到了sun.misc.Unsafe软件包,并对它能做的事情感到惊讶。
当然,这个class没有证件,但是我想知道是否有使用它的好理由。 哪些情况下可能会出现需要使用的情况? 在真实世界的场景中如何使用它?
而且,如果你确实需要它,那么这是不是表明你的devise有可能是错的?
为什么Java甚至包含这个类?
例子
-
虚拟机“内在化”。 即在无锁哈希表中使用CAS(比较和交换)例如:sun.misc.Unsafe.compareAndSwapInt它可以使真正的JNI调用本地代码包含CAS
在这里阅读更多关于CAS的http://en.wikipedia.org/wiki/Compare-and-swap
-
主机VM的sun.misc.Unsafefunction可用于分配未初始化的对象,然后将构造函数的调用解释为其他任何方法调用。
-
可以从本地地址跟踪数据。可以使用java.lang.Unsafe类检索对象的内存地址,并通过不安全的get / put方法直接在其字段上操作!
-
编译JVM的时间优化。 高性能虚拟机使用“魔术”,需要低级别的操作。 例如: http : //en.wikipedia.org/wiki/Jikes_RVM
-
分配内存,sun.misc.Unsafe.allocateMemory例如: – 当调用ByteBuffer.allocateDirect时,DirectByteBuffer构造函数在内部调用它
-
跟踪调用堆栈并重放由sun.misc.Unsafe实例化的值,对于检测很有用
-
sun.misc.Unsafe.arrayBaseOffset和arrayIndexScale可用于开发arraylets,这是一种将大型数组高效分解为较小对象的技术,以限制大型对象的扫描,更新或移动操作的实时成本
-
http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java
更多关于这里的参考 – http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html
只是从一些代码search引擎运行search ,我得到以下例子:
- Java对象表示法 – 使用它来更有效的数组处理,引用javadoc
简单的类来获得对不安全对象的访问。 {@link Unsafe} *是必需的,以允许在数组上进行高效的CAS操作。 请注意,{@link java.util.concurrent.atomic}中的版本(如{@link java.util.concurrent.atomic.AtomicLongArray})需要额外的内存sorting保证,这些algorithm一般不需要,而且也很昂贵在大多数处理器上
- SoyLatte – java 6的osx javadoc摘录
/ **用于静态字段的基于sun.misc.Unsafe的FieldAccessors的基类。 从reflection代码的观点来看,只有九种types的字段:八种基本types和对象。 使用类Unsafe而不是生成的字节码可节省dynamic生成的FieldAccessors的内存和加载时间。 * /
- SpikeSource公司
/ *通过电线发送的FinalFields ..如何在接收端解组并重新创build对象? 我们不想调用构造函数,因为它会为final字段build立值。 我们必须像发件人一样重新创build最后一个字段。 sun.misc.Unsafe为我们做这个。 * /
还有很多其他的例子,只要按照上面的链接…
有趣的是,我从来没有听说过这个class(这真的是一件好事)。
有一点需要注意的是,使用Unsafe#setMemory将包含敏感信息的缓冲区(密码,键,…)归零。 你甚至可以这样做到“不可变”对象的字段(然后,我想老式的reflection也可能在这里)。 尽pipe如此,我还是没有安全专家。
Unsafe.throwException – 允许抛出检查的exception而不用声明它们。
这在处理reflection或AOP的某些情况下很有用。
假设您为用户定义的接口构build通用代理。 用户可以通过在特殊情况下通过在界面中声明exception来指定抛出exception。 那么这是我知道的唯一方法,在接口的dynamic实现中引发一个检查的exception。
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(); } }
基于对使用eclipse进行参考跟踪的Java 1.6.12库的简要分析,似乎Unsafe
每个有用function都以有用的方式公开。
CAS操作通过Atomic *类暴露。 内存操作函数通过DirectByteBuffer同步指令(park,unpark)公开,通过AbstractQueuedSynchronizer暴露出来,然后由Lock实现使用。
class级不安全
用于执行低级别,不安全操作的一组方法。 尽pipe类和所有方法都是公共的,但是这个类的使用是有限的,因为只有受信任的代码才能获得它的实例。
它的一个用途是在java.util.concurrent.atomic
类中:
- AtomicIntegerArray
- AtomicLongArray
对于有效的内存复制(至less比System.arraycopy()更快的复制); 正如Java LZF和Snappy编解码器所使用的。 他们使用'getLong'和'putLong',比逐字节复制要快。 在复制诸如16/32/64字节块的东西时尤其有效。
使用它可以高效地访问和分配大量内存,例如在您自己的体素引擎中! (即我的世界风格的游戏。)
根据我的经验,JVM常常无法消除您真正需要的边界检查。 例如,如果您正在迭代大型数组,但是实际的内存访问被隐藏在循环中的非虚方法调用之下,则JVM仍然可以对每个数组访问执行边界检查,而不是之前的一次循环。 因此,为了获得潜在的性能提升,可以通过一个使用sun.misc.Unsafe直接访问内存的方法来消除循环内部的JVM边界检查,确保在正确的位置检查自己的边界。 (你会在某个级别检查,对不对?)
*由非虚拟的,我的意思是JVM不应该dynamic地解决你的特定方法,因为你已经正确地保证类/方法/实例是静态/最终/你有什么组合。
对于我自己生成的体素引擎,这导致了在块生成和序列化(我正在读取/写入整个arrays的低价位)时显着的性能增益。 结果可能会有所不同,但如果缺less边界消除是你的问题,那么这将解决它。
这里有一些潜在的主要问题:特别是,当你提供访问内存的能力而无需边界检查你的接口的客户端时,他们可能会滥用它。 (不要忘记,黑客也可以是你的界面的客户,特别是在用Java编写的体素引擎的情况下)。因此,你应该devise你的界面的方式,使内存访问不能被滥用,或者您应该非常小心地validation用户数据,然后再与您的危险界面混合。 考虑到黑客可以用不受限制的内存访问的灾难性事情,最好采取两种方法。
我最近正在重新实现JVM,发现在Unsafe
方面实现了令人惊讶的数量的类。 该类主要是为Java库实现者devise的,并且包含了基本上不安全但是构build快速原语所必需的function。 例如,有一些获取和写入原始字段偏移量的方法,使用硬件级同步,分配和释放内存等。它不打算被普通的Java程序员使用。 它是无证的,特定于实现的,本质上是不安全的(因此名称!)。 而且,我认为SecurityManager
几乎在所有情况下都不允许访问它。
简而言之,它主要允许库实现者访问底层机器,而不必像AtomicInteger
native那样声明每个方法。 在常规的Java编程中,您不需要使用或担心它,因为整个过程要使其他库足够快,以至于不需要这种访问。
堆外采集对分配大量内存非常有用,并在使用后立即释放,无需GC干扰。 我写了一个库,用于基于sun.misc.Unsafe
的堆外数组/列表。
Unsafe.park()
和Unsafe.unpark()
用于构build自定义并发控制结构和协作调度机制。
我们已经实现了巨大的集合,如数组,HashMaps,使用不安全的TreeMaps。
为了避免/最小化碎片,我们使用了不安全的dlmalloc概念来实现内存分配器。
这有助于我们获得并发性能。
我自己并没有使用它,但是我想如果你有一个只能偶尔被多个线程读取的variables(所以你不想让它变成volatile),你可以在主线程中使用putObjectVolatile
readObjectVolatile
在执行罕见的读取其他线程时。
其中一个例子就是随机方法,它调用不安全的方法来改变种子 。
这个网站也有它的一些用途 。
该对象似乎可用性低于Java代码通常允许的级别。 如果您正在编写高级应用程序,那么JVM会将内存处理和其他操作从代码级别中抽象出来,以便于编程。 通过使用不安全库,您可以有效地完成通常为您完成的低级操作。
正如woliveirajr所说,“随机()”使用不安全来播种,就像许多其他操作将使用不安全中包含的allocateMemory()函数一样。
作为一名程序员,你可能不需要这个库,但是对低级元素有严格的控制确实派上用场(这就是为什么在主要产品中仍然存在程序集和(在较小程度上)C代码)
如果您需要replace当前使用它的某个类提供的function,则需要它。
这可以是自定义/更快/更紧凑的序列化/反序列化,ByteBuffer的更快/更大的缓冲器/可resize的版本,或添加一个primefacesvariables,例如当前不支持的primefacesvariables。
我曾经在一些时候用过这些。