为什么sun.misc.Unsafe存在,它如何在现实世界中使用?

pde*_*eva 267 java unsafe

前几天我遇到了sun.misc.Unsafe包裹,并对它能做什么感到惊讶.

当然,这门课没有证件,但我想知道是否有充分的理由使用它.您可能需要使用哪些场景?它如何在现实场景中使用?

此外,如果您确实需要它,那是否表明您的设计可能出现问题?

为什么Java甚至包括这个类?

zud*_*kod 159

例子

  1. VM"内在化".即无锁散列表中使用的CAS(比较和交换)例如:sun.misc.Unsafe.compareAndSwapInt它可以将真正的JNI调用转换为包含CAS特殊指令的本机代码

    在这里阅读更多关于CAS的信息http://en.wikipedia.org/wiki/Compare-and-swap

  2. 主机VM的sun.misc.Unsafe功能性可以被用于分配未初始化的对象,然后解释该构造函数调用的任何其他方法调用.

  3. 人们可以追踪本地address.It可以使用java.lang.Unsafe类检索对象的内存地址中的数据,并在其领域直接通过不安全的get/put方法操作!

  4. 编译JVM的时间优化.高性能VM使用"魔术",需要低级操作.例如:http://en.wikipedia.org/wiki/Jikes_RVM

  5. 分配内存,sun.misc.Unsafe.allocateMemory例如: - 当调用ByteBuffer.allocateDirect时,DirectByteBuffer构造函数在内部调用它

  6. 跟踪调用堆栈并使用sun.misc.Unsafe实例化的值进行重放,这对于检测非常有用

  7. sun.misc.Unsafe.arrayBaseOffset和arrayIndexScale可用于开发arraylets,这是一种有效地将大型数组拆分为较小对象的技术,以限制在大型对象上扫描,更新或移动操作的实时成本

  8. http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java

更多关于这里的参考 - http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html


Asa*_*saf 31

只是在某些代码搜索引擎中运行搜索,我得到以下示例:

用于访问{@link Unsafe}对象的简单类.{@link Unsafe}*是允许对阵列进行高效CAS操作所必需的.请注意,{@link java.util.concurrent.atomic}中的版本,例如{@link java.util.concurrent.atomic.AtomicLongArray},需要额外的内存排序保证,这些保证通常在这些算法中不需要并且也很昂贵在大多数处理器上

  • SoyLatte - java 6 for osx javadoc excerpt

/**用于静态字段的基于sun.misc.Unsafe的FieldAccessors的基类.观察结果是,从反射代码的角度来看,只有九种类型的字段:八种基本类型和对象.使用类Unsafe而不是生成的字节码可以为动态生成的FieldAccessor节省内存和加载时间.*/

  • SpikeSource公司

/*通过网络发送的FinalFields ..如何在接收端解组并重新创建对象?我们不想调用构造函数,因为它会为最终字段建立值.我们必须重新创建最终字段,就像发送方一样.sun.misc.Unsafe为我们这样做.*/

还有很多其他的例子,只需按照上面的链接...


Mik*_*els 24

有意思,我从来没有听说过这个课程(这可能是一件好事,真的).

跳到脑海的一件事是使用Unsafe#setMemory将包含敏感信息的缓冲区归零(密码,密钥......).你甚至可以对"不可变"对象的字段执行此操作(然后我再次假设普通的旧反射也可以在这里做到这一点).我不是安全专家,所以不管怎么说.

  • 从来没有听说过它,但我喜欢他们的`park()`文档:"阻止当前线程,当发生平衡取消停止时返回,或者已经发生平衡unpark,或线程被中断,或者,如果不是绝对和时间不是零,给定的时间纳秒已经过去,或者如果是绝对的,那么自Epoch过去以来,给定的截止时间(以毫秒为单位),或者是虚假的(即,没有"理由"返回)_".几乎和"程序退出时释放内存一样好,或者以随机间隔释放,以先到者为准". (38认同)
  • 没有任何意义,因为Java使用复制世代垃圾收集器,并且您的敏感信息很可能已经位于"空闲"内存中等待被覆盖的其他位置. (7认同)
  • "我从来没有听说过这堂课......我已经多次告诉过你了!*叹*+ :( (4认同)

Tim*_*der 22

基于对使用eclipse进行参考跟踪的Java 1.6.12库的非常简短的分析,似乎每个有用的功能Unsafe都以有用的方式公开.

CAS操作通过Atomic*类公开.内存操作函数通过DirectByteBuffer公开同步指令(park,unpark)通过AbstractQueuedSynchronizer公开,而AbstractQueuedSynchronizer又由Lock实现使用.


Ral*_*lph 21

Unsafe.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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你可以做同样的w /`Thread.stop(Throwable)`不需要不安全,在同一个线程中你可以抛出任何东西(没有编译检查) (14认同)

Mar*_*gus 10

不安全

用于执行低级别,不安全操作的方法的集合.虽然类和所有方法都是公共的,但是这个类的使用是有限的,因为只有受信任的代码才能获得它的实例.

它的一个用途是在java.util.concurrent.atomic课堂上:


Sta*_*Man 6

用于高效的内存复制(至少对于短块,比System.arraycopy()复制更快); 正如Java LZFSnappy编解码器所使用的那样.他们使用'getLong'和'putLong',这比逐字节复制更快; 复制16/32/64字节块之类的东西时特别有效.


tem*_*def 5

我最近正在重新实现JVM,发现在方面实现了惊人数量的类Unsafe。该类主要是为Java库实现者设计的,并且包含从本质上讲是不安全的但对于构建快速基元是必需的功能。例如,存在一些获取和写入原始字段偏移量,使用硬件级同步,分配和释放内存等的方法。普通Java程序员不打算使用它。它是无证的,特定于实现的,并且本质上是不安全的(因此得名!)。而且,我认为SecurityManager在几乎所有情况下,该方法都将禁止使用它。

简而言之,主要是允许库实现者访问底层计算机,而不必在某些类(例如AtomicIntegernative)中声明每个方法。您不需要在常规Java编程中使用或担心它,因为重点是使其余库足够快,以至于您不需要这种访问。


ale*_*sko 5

堆外收集对于分配大量内存并在使用后立即释放它而不受 GC 干扰可能很有用。我编写了一个库,用于处理基于sun.misc.Unsafe.


Phi*_*lip 5

使用它可以有效地访问和分配大量内存,例如在您自己的体素引擎中!(即Minecraft风格的游戏.)

根据我的经验,JVM通常无法消除您真正需要的边界检查.例如,如果您正在迭代一个大型数组,但实际的内存访问隐藏在循环中的非虚拟*方法调用下,则JVM仍然可以对每个数组访问执行边界检查,而不是之前的一次循环.因此,为了获得潜在的大性能提升,您可以通过使用sun.misc.Unsafe直接访问内存的方法来消除循环内部的JVM边界检查,确保在正确的位置自行进行任何边界检查.(你要去边界检查在一定程度上,对吧?)
*由非虚,我指的是JVM不应该动态地解决无论你的具体方法是,因为你已经正确地保证类/方法/实例是一些静态/最终/有什么你的组合.

对于我自己开发的体素引擎,这在块生成和序列化过程中产生了显着的性能提升(我在一起读取/写入整个阵列的地方).结果可能会有所不同,但如果缺少边界消除是你的问题,那么这将解决它.

这有一些潜在的主要问题:具体来说,当您提供访问内存的能力而无需对接口的客户端进行边界检查时,他们可能会滥用它.(不要忘记,黑客也可以是你的界面的客户端...特别是在用Java编写的体素引擎的情况下.)因此,你应该设计你的界面,使得内存访问不会被滥用,或者你应该非常小心,以验证用户数据,则可以不断,之前曾经与你的危险接口打成一片.考虑到黑客可以通过未经检查的内存访问进行的灾难性事情,最好采用这两种方法.


小智 5

我们使用 Unsafe 实现了像 Arrays、HashMaps、TreeMaps 这样的巨大集合。
为了避免/最小化碎片,我们使用dlmalloc的概念而不是不安全的概念来实现内存分配器。
这帮助我们获得了并发性能。


Mat*_*ogt 1

我自己没有使用过它,但我想如果你有一个变量只是偶尔被多个线程读取(所以你真的不想让它变得易失)你可以putObjectVolatile在主线程中写入它时使用readObjectVolatile当从其他线程进行罕见的读取时。