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

时间:2011-04-06 23:38:03

标签: java unsafe

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

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

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

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

16 个答案:

答案 0 :(得分:156)

实施例

  1. VM“内在化”。即无锁哈希表中使用的CAS(比较和交换) 例如:sun.misc.Unsafe.compareAndSwapInt 它可以将真正的JNI调用转换为包含CAS

    特殊指令的本机代码

    在此处详细了解CAS http://en.wikipedia.org/wiki/Compare-and-swap

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

  3. 可以从本机地址跟踪数据。可以检索 对象的内存地址使用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

  9. 有关此处参考资料的更多信息 - http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html

答案 1 :(得分:31)

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

  

获取{@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而不是生成       字节码可以节省内存和加载时间       动态生成的FieldAccessors。 * /

  • SpikeSource的
  

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

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

答案 2 :(得分:24)

有趣的是,我从来没有听说过这门课(这可能是一件好事,真的)。

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

答案 3 :(得分:22)

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

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

答案 4 :(得分: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();
    }
}

答案 5 :(得分:9)

  

班级Unsafe

     

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

它的一个用途是java.util.concurrent.atomic类:

答案 6 :(得分:6)

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

答案 7 :(得分:5)

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

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

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

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

答案 8 :(得分:4)

我最近正致力于重新实现JVM,并发现在Unsafe方面实现了数量惊人的类。该类主要是为Java库实现者设计的,包含从根本上说不安全但是构建快速原语所必需的功能。例如,有一些方法可以获取和写入原始字段偏移,使用硬件级同步,分配和释放内存等。它不适合普通的Java程序员使用;它没有文档,特定于实现,并且本质上不安全(因此名称!)。此外,我认为SecurityManager几乎在所有情况下都不允许访问它。

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

答案 9 :(得分:4)

堆外集合可用于分配大量内存并在使用后立即解除分配,而不会产生GC干扰。我写了一个library来处理基于sun.misc.Unsafe的堆外数组/列表。

答案 10 :(得分:3)

Unsafe.park()Unsafe.unpark()用于构建自定义并发控制结构和协作调度机制。

答案 11 :(得分:3)

我们已经实现了大量集合,如Arrays,HashMaps,TreeMaps使用Unsafe。
为了避免/最小化碎片,我们使用dlmalloc概念来实现内存分配器而不安全。
这有助于我们获得并发性能。

答案 12 :(得分:1)

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

答案 13 :(得分:1)

答案 14 :(得分:1)

如果您需要替换当前使用它的某个类提供的功能,则需要它。

这可以是自定义/更快/更紧凑的序列化/反序列化,更快/更大的缓冲/可调整大小的ByteBuffer版本,或者添加原子变量,例如目前尚不支持。

我已经在某个时候使用它了所有这些。

答案 15 :(得分:0)

该对象似乎可以在比Java代码通常允许的更低级别工作。如果您正在编写高级应用程序,那么JVM会从代码级别抽象出内存处理和其他操作,因此更容易编程。通过使用Unsafe库,您可以有效地完成通常为您完成的低级操作。

正如woliveirajr所说“random()”使用Unsafe来播种,因为许多其他操作将使用Unsafe中包含的allocateMemory()函数。

作为一名程序员,你可能可以逃脱,从不需要这个库,但是对低级元素进行严格控制确实会派上用场(这就是为什么仍有大会和(在较小程度上)C代码在主要产品中漂移的原因)