不安全的java类-Unsafe

作者: 图乐 | 来源:发表于2017-11-04 17:09 被阅读44次

本文基于Android N源码分析

前言
Java最初被设计为一种安全的受控环境。尽管如此,HotSpot还是包含了一个后门sun.misc.Unsafe,提供了一些可以直接操控内存和线程的底层操作。Unsafe被JDK广泛应用于java.nio和并发包等实现中,这个不安全的类提供了一个观察HotSpot JVM内部结构并且可以对其进行修改,但是不建议在生产环境中使用。
/**
 * 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.
 *
 * @author John R. Rose
 * @see #getUnsafe
 */

执行低级、不安全操作的方法的集合,尽管类和所有方法都是公共的,但是这个类的使用是有限的,因为只有受信任的代码才能获取它的实例。这是在Android 源码中对这个类的注释。

  • Unsafe位于sun.misc包内,可以通过native方法直接操作堆外内存,可以随意查看及修改JVM中运行时的数据结构,例如查看和修改对象的成员,Unsafe的操作粒度不是类,而是数据和地址。
  • 如何获得Unsafe对象,Unsafe类里面可以看到有一个getUnsafe方法:
   /**
     * Gets the unique instance of this class. This is only allowed in
     * very limited situations.
     */
    public static Unsafe getUnsafe() {
        /*
         * Only code on the bootclasspath is allowed to get at the
         * Unsafe instance.
         */
        ClassLoader calling = VMStack.getCallingClassLoader();
        if ((calling != null) && (calling != Unsafe.class.getClassLoader())) {
            throw new SecurityException("Unsafe access denied");
        }

        return THE_ONE;
    }

通过注释我们可以看出这个方法使用情况有限,只有在bootclasspath里面的代码才允许运行。如果我们想使用的话也不是没有办法那就是反射。
在java环境

public static Unsafe getUnsafe() {
   try {
           Field f = Unsafe.class.getDeclaredField("theUnsafe");
           f.setAccessible(true);
           return (Unsafe)f.get(null);
   } catch (Exception e) { 
       /* ... */
   }
}

android API下面无法直接获取到Unsafe这个类

    static {
        try {
            unsafeClass = Class.forName("sun.misc.Unsafe");
            if (Build.VERSION.SDK_INT >= 19) {
                Field theUnsafeInstance = unsafeClass.getDeclaredField("theUnsafe");
                theUnsafeInstance.setAccessible(true);
                unsafe = theUnsafeInstance.get(null);
            } else {
                Class AQSClass = Class.forName("java.util.concurrent.locks.AbstractQueuedSynchronizer");
                Field theUnsafeInstance = AQSClass.getDeclaredField("unsafe");
                theUnsafeInstance.setAccessible(true);
                unsafe = theUnsafeInstance.get(null);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

要在Java层操作内容,也不是没有办法做到;JDK给我们留了一个后门:sun.misc.Unsafe 类;在OpenJDK里面这个类灰常强大,从内存操作到CAS到锁机制,但是在Android 平台还有一点点不一样,在 Android N之前,Android的JDK实现是 Apache Harmony,这个实现里面的Unsafe就有点鸡肋了,没法写内存;好在Android 又开了一个后门:Memory 类。


java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作,主要提供了以下功能:

  1. 通过Unsafe类可以对内存进行操作;
    reallocateMemory方法并没有(N之前没有)
public native long allocateMemory(long bytes);//分配内存
public native void freeMemory(long address);//释放内存
public native void copyMemory(long srcAddr, long dstAddr, long bytes);//复制内存
public native int addressSize();
public native int pageSize();
  1. 可以定位对象某字段的内存位置,也可以修改对象的字段值,即使它是私有的;
/**
     * Gets the offset from the start of an array object's memory to
     * the memory used to store its initial (zeroeth) element.
     *
     * @param clazz non-null; class in question; must be an array class
     * @return the offset to the initial element
     */
    public int arrayBaseOffset(Class clazz) {}

    /**
     * Gets the size of each element of the given array class.
     *
     * @param clazz non-null; class in question; must be an array class
     * @return > 0; the size of each element of the array
     */
    public int arrayIndexScale(Class clazz) {}

    /**
     * Allocates an instance of the given class without running the constructor.
     * The class' <clinit> will be run, if necessary.
     */
    public native Object allocateInstance(Class<?> c);
  1. 挂起与恢复
    通过park方法挂起当前调用线程,通过unpark恢复一个线程(参数),线程操作相关还有一个LockSupport类的封装。
 /**
     * Parks the calling thread for the specified amount of time,
     * unless the "permit" for the thread is already available (due to
     * a previous call to {@link #unpark}. This method may also return
     * spuriously (that is, without the thread being told to unpark
     * and without the indicated amount of time elapsing).
     *
     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
     * in-depth information of the behavior of this method.</p>
     *
     * @param absolute whether the given time value is absolute
     * milliseconds-since-the-epoch true or relative
     * nanoseconds-from-now false
     * @param time the (absolute millis or relative nanos) time value
     */
    public void park(boolean absolute, long time) {
        if (absolute) {
            Thread.currentThread().parkUntil$(time);
        } else {
            Thread.currentThread().parkFor$(time);
        }
    }

    /**
     * Unparks the given object, which must be a {@link Thread}.
     *
     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
     * in-depth information of the behavior of this method.</p>
     *
     * @param obj non-null; the object to unpark
     */
    public void unpark(Object obj) {
        if (obj instanceof Thread) {
            ((Thread) obj).unpark$();
        } else {
            throw new IllegalArgumentException("valid for Threads only");
        }
    }
  1. CAS操作
    是通过compareAndSwapXXX方法实现的
 /**
     * Performs a compare-and-set operation on an int
     * field within the given object.
     *
     * @param obj non-null; object containing the field
     * @param offset offset to the field within obj
     * @param expectedValue expected value of the field
     * @param newValue new value to store in the field if the contents are
     * as expected
     * @return true if the new value was in fact stored, and
     * false if not
     */
    public native boolean compareAndSwapInt(Object obj, long offset,
            int expectedValue, int newValue);

相关文章

  • Unsafe类

    Unsafe类是Java不对外提供的不安全的类,juc包中的atomic*类都是用这个类实现的 // Uns...

  • Netty源码学习(6)--pipeline学习2

    Unsafe unsafe是不安全的意思,不要在应用程序里面直接使用Unsafe以及他的衍生类对象。Unsafe ...

  • 不安全的java类-Unsafe

    本文基于Android N源码分析 执行低级、不安全操作的方法的集合,尽管类和所有方法都是公共的,但是这个类的使用...

  • 关于Unsafe类的一点研究

    Unsafe类是java中非常特别的一个类。它名字就叫做“不安全”,提供的操作可以直接读写内存、获得地址偏移值、锁...

  • Unsafe类初探

    Unsafe类说明 从这个类的名字Unsafe上来说这个类就是一个不安全的类,也是不开放给用户直接使用的(当然我们...

  • Unsafe类源码解析

    前言 Unsafe,顾名思义,一个不安全的类,那么jdk的开发者为什么要设计一个不安全的类呢?这个类为什么会不安全...

  • 【安卓逆向】Java中的魔术类

    简单谈一谈Java中的Unsafe类 Unsafe类是啥? Java最初被设计为一种安全的受控环境。尽管如此,Ja...

  • Unsafe 与 LockSupport

    1.Unsafe java concurrent 包的基础是CAS, 而进行CAS操作的就是这个 Unsafe类....

  • 一起读读JAVA源码-Atomic

    AtomicBoolean AtomicInteger 解释 核心操作类Unsafe,JAVA提供工具类unsaf...

  • AtomicInteger源码分析

    **AtomicInteger** 是Java提供的原子操作类,其内部通过 **UnSafe** 工具类,使用 =...

网友评论

    本文标题:不安全的java类-Unsafe

    本文链接:https://www.haomeiwen.com/subject/bsgfmxtx.html