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

发布于 2024-10-31 04:24:25 字数 179 浏览 1 评论 0原文

前几天我偶然发现了 sun.misc.Unsafe 包,并对它的功能感到惊讶。

当然,该类没有记录,但我想知道是否有充分的理由使用它。可能会出现哪些场景需要使用它?它如何在现实场景中使用?

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

为什么Java还要包含这个类呢?

I came across the sun.misc.Unsafe package the other day and was amazed at what it could do.

Of course, the class is undocumented, but I was wondering if there was ever a good reason to use it. What scenarios might arise where you would need to use it? How might it be used in a real-world scenario?

Furthermore, if you do need it, does that not indicate that something is probably wrong with your design?

Why does Java even include this class?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

情释 2024-11-07 04:24:25

示例

  1. VM“内在化”。即无锁哈希表中使用的 CAS(比较和交换)
    例如:sun.misc.Unsafe.compareAndSwapInt
    它可以对包含 CAS 特殊指令的本机代码进行真正的 JNI 调用

    在此处了解有关 CAS 的更多信息 http://en.wikipedia.org/wiki/Compare-and-swap< /a>

  2. 主机虚拟机的 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 时,

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

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

  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

examples

  1. VM "intrinsification." ie CAS (Compare-And-Swap) used in Lock-Free Hash Tables
    eg:sun.misc.Unsafe.compareAndSwapInt
    it can make real JNI calls into native code that contains special instructions for CAS

    read more about CAS here http://en.wikipedia.org/wiki/Compare-and-swap

  2. The sun.misc.Unsafe functionality of the host VM can be used to allocate uninitialized objects and then interpret the constructor invocation as any other method call.

  3. One can track the data from the native address.It is possible to retrieve an
    object’s memory address using the java.lang.Unsafe class, and operate on its fields directly via unsafe get/put methods!

  4. Compile time optimizations for JVM. HIgh performance VM using "magic", requiring low-level operations. eg: http://en.wikipedia.org/wiki/Jikes_RVM

  5. Allocating memory, sun.misc.Unsafe.allocateMemory eg:- DirectByteBuffer constructor internally calls it when ByteBuffer.allocateDirect is invoked

  6. Tracing the call stack and replaying with values instantiated by sun.misc.Unsafe, useful for instrumentation

  7. sun.misc.Unsafe.arrayBaseOffset and arrayIndexScale can be used to develop arraylets,a technique for efficiently breaking up large arrays into smaller objects to limit the real-time cost of scan, update or move operations on large objects

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

more on references here - http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html

泡沫很甜 2024-11-07 04:24:25

仅通过运行 搜索 在一些代码搜索引擎中,我得到以下示例:

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

  • SoyLatte - java 6 for osx javadoc 摘录

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

  • 尖峰源

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

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

Just from running a search in some code search engine I get the following examples:

Simple class to obtain access to the {@link Unsafe} object. {@link Unsafe}
* is required to allow efficient CAS operations on arrays. Note that the
versions in {@link java.util.concurrent.atomic}, such as {@link
java.util.concurrent.atomic.AtomicLongArray}, require extra memory ordering
guarantees which are generally not needed in these algorithms and are also
expensive on most processors.

  • SoyLatte - java 6 for osx javadoc excerpt

/** Base class for sun.misc.Unsafe-based FieldAccessors for static
fields. The observation is that there are only nine types of
fields from the standpoint of reflection code: the eight primitive
types and Object. Using class Unsafe instead of generated
bytecodes saves memory and loading time for the
dynamically-generated FieldAccessors. */

  • SpikeSource

/*
FinalFields that are sent across the wire .. how to unmarshall and recreate the object on the
receiving side? We don't want to invoke the constructor since it would establish values for
final fields. We have to recreate the final field exactly like it was on the sender side.
The sun.misc.Unsafe does this for us.
*/

There are many other examples, just follow the above link...

不念旧人 2024-11-07 04:24:25

有趣的是,我什至从未听说过这个课程(这可能是一件好事,真的)。

我想到的一件事是使用 Unsafe#setMemory 将包含某一点敏感信息(密码、密钥等)的缓冲区归零。您甚至可以对“不可变”对象的字段执行此操作(我再次认为普通的旧反射也可以在这里发挥作用)。不过,我不是安全专家,所以对此持保留态度。

Interesting, I'd never even heard of this class (which is probably a good thing, really).

One thing that jumps to mind is using Unsafe#setMemory to zeroize buffers that contained sensitive information at one point (passwords, keys, ...). You could even do this to fields of "immutable" objects (then again I suppose plain old reflection might do the trick here too). I'm no security expert though so take this with a grain of salt.

暮倦 2024-11-07 04:24:25

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

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

Based on a very brief analysis of the Java 1.6.12 library using eclipse for reference tracing, it seems as though every useful functionality of Unsafe is exposed in useful ways.

CAS operations are exposed through the Atomic* classes.
Memory manipulations functions are exposed through DirectByteBuffer
Sync instructions (park,unpark) are exposed through the AbstractQueuedSynchronizer which in turn is used by Lock implementations.

琉璃繁缕 2024-11-07 04:24:25

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();
    }
}

Unsafe.throwException - allows to throw checked exception without declaring them.

This is useful in some cases where you deal with reflection or AOP.

Assume you Build a generic proxy for a user defined Interface. And the user can specify which exception is thrown by the implmentation in a special case just by declaring the exception in the interface. Then this is the only way I know, to rise a checked exception in the Dynamic Implementation of the Interface.

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();
    }
}
°如果伤别离去 2024-11-07 04:24:25

不安全

用于执行低级、不安全操作的方法集合。尽管该类和所有方法都是公共的,但该类的使用受到限制,因为只有受信任的代码才能获取它的实例。

它的一种用途是在 java.util.concurrent.atomic 类中:

Class Unsafe

A collection of methods for performing low-level, unsafe operations. Although the class and all methods are public, use of this class is limited because only trusted code can obtain instances of it.

One use of it is in java.util.concurrent.atomic classes:

古镇旧梦 2024-11-07 04:24:25

为了高效的内存复制(至少对于短块来说复制速度比 System.arraycopy() 更快); Java LZFSnappy 使用> 编解码器。他们使用“getLong”和“putLong”,这比逐字节复制要快;在复制 16/32/64 字节块等内容时特别有效。

For efficient memory copy (faster to copy than System.arraycopy() for short blocks at least); as used by Java LZF and Snappy codecs. They use 'getLong' and 'putLong', which are faster than doing copies byte-by-byte; especially efficient when copying things like 16/32/64 byte blocks.

我喜欢麦丽素 2024-11-07 04:24:25

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

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

I was recently working on reimplementing the JVM and found that a surprising number of classes are implemented in terms of Unsafe. The class is mostly designed for the Java library implementers and contains features that are fundamentally unsafe but necessary for building fast primitives. For example, there are methods for getting and writing raw field offsets, using hardware-level synchronization, allocating and freeing memory, etc. It is not intended to be used by normal Java programmers; it's undocumented, implementation-specific, and inherently unsafe (hence the name!). Moreover, I think that the SecurityManager will disallow access to it in almost all cases.

In short, it mainly exists to allow library implementers access to the underlying machine without having to declare every method in certain classes like AtomicInteger native. You shouldn't need to use or worry about it in routine Java programming, as the whole point is to make the rest of the libraries fast enough that you wouldn't need that sort of access.

箜明 2024-11-07 04:24:25

堆外收集对于分配大量内存并在使用后立即释放内存而不产生 GC 干扰可能很有用。我编写了一个 ,用于基于 sun.misc 处理堆外数组/列表.不安全

Off-heap collections may be useful for allocating huge amounts of memory and deallocating it immediately after use without GC interference. I wrote a library for working with off-heap arrays/lists based on sun.misc.Unsafe.

策马西风 2024-11-07 04:24:25

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

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

开发的体素引擎,这在块生成和序列化期间(在我一次读取/写入整个数组的地方)带来了显着的性能提升。结果可能会有所不同,但如果您的问题是缺乏边界消除,那么这将解决它。

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

Use it to access and allocate large amounts of memory efficiently, such as in your very own voxel engine! (i.e. Minecraft-style game.)

In my experience, the JVM is often unable to eliminate bounds-checking in place you truly need it. For example, if you're iterating over a large array, but the actual memory access is tucked underneath a non-virtual* method call in the loop, the JVM may still perform a bounds check with each array access, rather than once just before the loop. Thus, for potentially large performance gains, you can eliminate JVM bounds-checking inside the loop via a method which employs sun.misc.Unsafe to access the memory directly, making sure to do any bounds-checking yourself at the correct places. (You are gonna bounds check at some level, right?)
*by non-virtual, I mean the JVM shouldn't have to dynamically resolve whatever your particular method is, because you've correctly guaranteed that class/method/instance are some combination of static/final/what-have-you.

For my home-grown voxel engine, this resulted in a dramatic performance gain during chunk generation and serialization (iow places where I was reading/writing to the entire array at once). Results may vary, but if a lack of bounds-elimination is your problem, then this will fix it.

There are some potentially major problems with this: specifically, when you provide the ability to access memory without bounds-checking to clients of your interface, they will probably abuse it. (Don't forget that hackers can also be clients of your interface... especially in the case of a voxel engine written in Java.) Thus, you should either design your interface in a way such that memory access cannot be abused, or you should be extremely careful to validate user-data before it can ever, ever mingle with your dangerous interface. Considering the catastrophic things a hacker can do with unchecked memory access, it's probably best to take both approaches.

我的鱼塘能养鲲 2024-11-07 04:24:25

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

We have implemented huge collections like Arrays,HashMaps,TreeMaps using Unsafe.
And to avoid/minimize the fragmentation, we implemented memory allocator using the concepts of dlmalloc over unsafe.
This helped us to gain the performance in concurrency.

猫性小仙女 2024-11-07 04:24:25

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

Unsafe.park() and Unsafe.unpark() for the construction of custom concurrency control structures and cooperative scheduling mechanisms.

成熟稳重的好男人 2024-11-07 04:24:25

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

Haven't used it myself, but I suppose if you have a variable that is only occasionally read by more than one thread (so you don't really want to make it volatile) you could use the putObjectVolatile when writing it in the main thread and readObjectVolatile when doing the rare reads from other threads.

分开我的手 2024-11-07 04:24:25

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

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

我曾经用过它来完成所有这些工作。

You need it if you need to replace functionality provided by one of the classes which uses it currently.

This can be custom/faster/more compact serialization/deserialization, a faster/larger buffer/resizable version of ByteBuffer, or adding an atomic variable e.g. one not supported currently.

I have used it for all of these at some time.

欢烬 2024-11-07 04:24:25

其使用的一个示例是 random 方法,该方法 调用 unsafe 来更改种子

该网站也有一些它的用途

One example of its use is the random method, which calls the unsafe to change the seed.

This site also has also some uses of it.

千紇 2024-11-07 04:24:25

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

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

作为一名程序员,您可能永远不需要这个库,但对低级元素的严格控制确实会派上用场(这就是为什么在主要产品中仍然存在汇编和(在较小程度上)C 代码)

The object appears to be availability to work at a lower level than what Java code typically allows for. If you're coding a high level application then the JVM abstracts memory handling and other operations away from the code level so its easier to program. By using the Unsafe library you're effectively completing low-level operations that would typically be done for you.

As woliveirajr stated "random()" uses Unsafe to seed just as many other operations will use the allocateMemory() function included in Unsafe.

As a programmer you probably could get away with never needing this library but having strict control over low-level elements does come in handy (that's why there is still Assembly and (to a lesser extent) C code drifting around in major products)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文