• Java可以如何直接访问内存?
  • 发布于 2个月前
  • 512 热度
    0 评论
Java最初被设计为一种安全的受控环境。尽管如此,Java HotSpot还是包含了一个“后门”,提供了一些可以直接操控内存和线程的低层次操作。这个后门类——sun.misc.Unsafe——被JDK广泛用于自己的包中,如java.nio和java.util.concurrent。这个类在JDK中有广泛的应用,例如,java.nio和java.util.concurrent、Netty、Caffeine。

但是丝毫不建议随意使用这个后门。因为这个API十分不安全、不轻便、而且不稳定。很难想象在日常开发中使用这些危险的,不可移植和未经校验的API。然而,Unsafe提供一种简单的方法来观察HotSpot JVM内部的一些技巧。

获取Unsafe
sun.misc.Unsafe这个类的访问是受限的,它的构造方法是私有的,相应的工厂方法要求必须被Bootloader载入才能使用,也就是说,只有JDK内部分才能使用这个工厂方法来构造Unsafe对象。
public final class Unsafe {

    …

    private Unsafe() {}
    // 堆代码 duidaima.com
    private static final Unsafe theUnsafe = new Unsafe();
    …
        public static Unsafe getUnsafe() {
        Class cc = sun.reflect.Reflection.getCallerClass(2);
        if (cc.getClassLoader() != null)
            throw new SecurityException(“Unsafe”);
        return theUnsafe;

    }
    …

}
幸运地是,有一个theUnsafe属性可以被利用来检索Unsafe实例,我们可以见到的写一个反射方法,来获取Unsafe实例:
public static Unsafe getUnsafe() {
    try {
        Field f = Unsafe.class.getDeclaredField(“theUnsafe”);
        f.setAccessible(true);
        return (Unsafe)f.get(null);
    } catch (Exception e) { /* … */ }
}
下面将看看一些Unsafe的方法。
1.对直接内存进行读写。
long getAddress(long address) 和void putAddress(long address, long x)
2.另一个类似的方法对直接内存进行读写,将C语言的结构体和Java对象进行转换。
int getInt(Object o, long offset) , void putInt(Object o, long offset, int x)
3.分配内存,可以看做是C语言的malloc()函数的一种包装
long allocateMemory(long bytes)
sun.misc.Unsafe提供了几乎是不受限制的监控和修改虚拟机运行时数据结构的能力。

尽管这些能力几乎是和Java开发本身不相干的,但是对于想要学习HotSpot虚拟机但是没有C++代码调试,或者需要去创建特别的分析工具的人来说,Unsafe是一个伟大的工具。
用户评论