我最近了解到sun.misc.Unsafe包,惊讶于它所能实现的功能。
当然,该类未被记录在文档中,但我想知道是否有使用它的充分理由。在哪些情况下可能需要使用它?在现实世界的场景中,它可能如何使用?
此外,如果您确实需要它,这是否不表示您的设计可能存在问题?
为什么Java甚至要包括这个类?
我最近了解到sun.misc.Unsafe包,惊讶于它所能实现的功能。
当然,该类未被记录在文档中,但我想知道是否有使用它的充分理由。在哪些情况下可能需要使用它?在现实世界的场景中,它可能如何使用?
此外,如果您确实需要它,这是否不表示您的设计可能存在问题?
为什么Java甚至要包括这个类?
例子
虚拟机“内部化”。例如,在无锁哈希表中使用CAS(比较和交换)。 例如:sun.misc.Unsafe.compareAndSwapInt 它可以将真正的JNI调用转换为包含CAS特殊指令的本地代码。
在此处阅读有关CAS的更多信息:http://en.wikipedia.org/wiki/Compare-and-swap
主机VM的sun.misc.Unsafe功能可用于分配未初始化的对象,然后将构造函数调用解释为任何其他方法调用。
可以跟踪来自本机地址的数据。使用java.lang.Unsafe类可以检索对象的内存地址,并通过不安全的get / put方法直接操作其字段!
JVM的编译时优化。使用“magic”实现高性能VM,需要低级操作。例如:http://en.wikipedia.org/wiki/Jikes_RVM
分配内存,sun.misc.Unsafe.allocateMemory例如:-当调用ByteBuffer.allocateDirect时,DirectByteBuffer构造函数会在内部调用它。
跟踪调用堆栈并使用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
仅从在一些代码搜索引擎上运行搜索,我得到以下示例:
简单的类,用于获取对{@link Unsafe}对象的访问。需要{@link Unsafe}以允许对数组进行高效的CAS操作。请注意,在{@link java.util.concurrent.atomic}中的版本(例如{@link java.util.concurrent.atomic.AtomicLongArray})需要额外的内存排序保证,这些保证通常不需要在这些算法中,并且在大多数处理器上也很昂贵。
/** 基于sun.misc.Unsafe的FieldAccessors的静态字段的基类。观察是,从反射代码的角度来看,只有九种类型的字段:八种基本类型和Object。使用Unsafe类而不是生成的字节码可节省内存和加载时间用于动态生成的FieldAccessors。*/
/*需要将FinalFields发送到网络上的情况下,如何在接收端解组并重新创建对象?我们不想调用构造函数,因为它会为final字段建立值。我们必须像发送方那样完全重新创建最终场。sun.misc.Unsafe为我们完成此操作。*/
还有许多其他例子,请遵循上面的链接...
有趣的是,我以前甚至没听说过这个类(其实这可能是一件好事)。
我想到的一个事情是使用Unsafe#setMemory来清零曾经包含敏感信息的缓冲区(密码、密钥等)。你甚至可以对“不可变”的对象的字段进行清零操作(尽管我认为普通的反射也可以解决这个问题)。但我不是安全专家,所以请带着点怀疑的态度。
park()
文档:"阻塞当前线程,并在发生平衡 unpark 时返回,或者已经发生了平衡 unpark,或者线程被中断,或者如果不是绝对时间并且时间不为零,则经过给定的时间纳秒,或者如果是绝对时间,则自 Epoch 以来经过了给定的截止日期(毫秒),_或出于无 '原因' 而虚假地返回_”。几乎和“内存在程序退出时释放,或在随机间隔中释放,以先到者为准”一样好。 - aroth通过使用Eclipse进行参考跟踪,对Java 1.6.12库进行简要分析后发现,似乎每个Unsafe
实用功能都以有用的方式暴露出来。
CAS操作通过Atomic *类公开。 内存操作函数通过DirectByteBuffer公开。 同步指令(park,unpark)通过AbstractQueuedSynchronizer公开,后者又由Lock实现使用。
LockSupport
公开,而不是AQS(后者更像是锁实现而不是park/unpark)。 - bestsssUnsafe.throwException - 允许在不声明异常的情况下抛出已检查异常。
这在处理反射或AOP时非常有用。
假设你为用户定义的接口构建了通用代理,并且用户可以通过在接口中声明异常来指定在特定情况下抛出的异常。那么这是我所知道的唯一方式,在接口的动态实现中引发已检查的异常。
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();
}
}
Thread.stop(Throwable)
完成相同的操作,无需使用不安全的方法。在同一线程中,你可以随意抛出任何异常(因为没有编译检查)。 - bestsss一组用于执行低级别,不安全操作的方法。尽管该类和所有方法都是公共的,但由于只有受信任的代码才能获得该类的实例,因此对该类的使用受到限制。
其一种用途是在java.util.concurrent.atomic
类中:
getLong/putLong
更好(而且你还需要计算地址)。 - bestsssgetLong
/ putLong
的组合时,我看到性能表现更好:理想情况下,为了简便和全部一致性,我更喜欢使用 System.arraycopy()
;但是,实际测试显示对于我测试的案例来说不太适用。 - StaxManUnsafe
实现的。这个类主要为Java库实现者设计,包含一些基本不安全但构建快速原语所必需的功能。例如,它有获取和写入原始字段偏移量的方法、使用硬件级别同步、分配和释放内存等方法。它不适合普通的Java程序员使用;它没有文档说明,是特定于实现的,并且本质上是不安全的(因此被命名为Unsafe)。此外,我认为SecurityManager
会在几乎所有情况下禁止访问它。AtomicInteger
这样的某些类中声明每个方法。您不应该在常规Java编程中使用或担心它,因为整个目的是使其余的库足够快,以至于您不需要那种访问方式。Unsafe.class.getDeclaredField("theUnsafe")
,并设置.setAccessible(true)
,然后使用.get(null)
也可以获取它。 - amara这种方法存在一些潜在的主要问题:具体来说,当您向客户端提供可以无需边界检查访问内存的能力时,他们可能会滥用它。(不要忘记黑客也可以成为您接口的客户端...特别是在Java编写的像素引擎的情况下。)因此,您应该设计您的接口,以使内存访问无法被滥用,或者您应该极其小心地验证用户数据,在它与您的危险接口混合之前,它必须是正确的。考虑到黑客可能使用未经检查的内存访问执行的灾难性事情,最好采用两种方法。