java不安全_不安全的java类-Unsafe

本文详细介绍了Java中的Unsafe类,它提供了底层内存操作和并发控制的功能,如内存分配、对象字段定位、CAS操作等。虽然不推荐在生产环境中直接使用,但Unsafe在JDK的某些实现中扮演关键角色。通过反射可以获取Unsafe实例,但其使用受到限制,主要在特定场景下如优化或理解JVM内部工作原理时使用。
摘要由CSDN通过智能技术生成

本文基于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类提供了硬件级别的原子操作,主要提供了以下功能:

通过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();

可以定位对象某字段的内存位置,也可以修改对象的字段值,即使它是私有的;

/**

* 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' will be run, if necessary.

*/

public native Object allocateInstance(Class> c);

挂起与恢复

通过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).

*

*

See {@link java.util.concurrent.locks.LockSupport} for more

* in-depth information of the behavior of this method.

*

* @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}.

*

*

See {@link java.util.concurrent.locks.LockSupport} for more

* in-depth information of the behavior of this method.

*

* @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");

}

}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值