`
lobin
  • 浏览: 425985 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多

Unsafe很强大,提供了一组底层(low-level)、unsafe的操作

 

Java Unsafe-获取对象内存地址,对象成员变量相对对象内存地址偏移量以及通过这种方式获取对象成员变量的值

Java Unsafe-获取对象成员变量相对对象内存地址偏移量

Java Unsafe获取对象成员变量相对对象内存地址偏移量

 

UnsafeTestKlass

public class UnsafeTestKlass {

 

    private int value;

    

    public UnsafeTestKlass() {

       this(99);

    }

    

    public UnsafeTestKlass(int value) {

       this.value = value;

    }

    

    public int value() {

       return value;

    }

}

获取Unsafe

private Unsafe getUnsafe() throws Throwable {

    Class<?> unsafeClass = Unsafe.class;

    for (Field f : unsafeClass.getDeclaredFields()) {

        if ("theUnsafe".equals(f.getName())) {

            f.setAccessible(true);

            return (Unsafe) f.get(null);

        }

    }

    throw new IllegalAccessException("no declared field: theUnsafe");

}

 

例子

@Test

public void getObjectFieldAddressOffset() throws Throwable {

    Field field = UnsafeTestKlass.class.getDeclaredField("value");

    Unsafe unsafe = getUnsafe();

    long valueOffset = unsafe.objectFieldOffset(field);

    System.out.println("value offset: " + valueOffset);

}

 

<!--EndFragment--> areastRtm-��B P]B r-fareast;mso-hansi-theme-font:minor-fareast; mso-bidi-font-family:"Courier New";color:black;mso-themecolor:text1; mso-font-kerning:0pt'>}

 

 

 

 

 

Java Unsafe获取对象内存地址,对象成员变量相对对象内存地址偏移量以及通过这种方式获取对象成员变量的值

 

UnsafeTestKlass

public class UnsafeTestKlass {

 

    private int value;

    

    public UnsafeTestKlass() {

       this(99);

    }

    

    public UnsafeTestKlass(int value) {

       this.value = value;

    }

    

    public int value() {

       return value;

    }

}

 

获取对象内存地址

public long location(Object object) throws Throwable {

Unsafe unsafe = getUnsafe();

       

Object[] array = new Object[] {object};

 

long baseOffset = unsafe.arrayBaseOffset(Object[].class);

int addressSize = unsafe.addressSize();

long location;

switch (addressSize) {

case 4:

location = unsafe.getInt(array, baseOffset);

           break;

       case 8:

           location = unsafe.getLong(array, baseOffset);

           break;

       default:

           throw new Error("unsupported address size: " + addressSize);

    }

    return (location);

}

 

获取Unsafe

private Unsafe getUnsafe() throws Throwable {

    Class<?> unsafeClass = Unsafe.class;

    for (Field f : unsafeClass.getDeclaredFields()) {

        if ("theUnsafe".equals(f.getName())) {

            f.setAccessible(true);

            return (Unsafe) f.get(null);

        }

    }

    throw new IllegalAccessException("no declared field: theUnsafe");

}

 

例子

/**

* here are three way to get the field value of an object:

 * 1: reflection

 * 2: address offset of field base object

 * 3: absolute address of the field of object:

 *    address of object + address offset of field base object 

 * 

 * @throws Throwable

 */

@Test

public void getObjectFieldValue() throws Throwable {

    UnsafeTestKlass klass = new UnsafeTestKlass();

 

    Field field = UnsafeTestKlass.class.getDeclaredField("value");

    field.setAccessible(true);

    int value1 = (Integer) field.get(klass);

    System.out.println("value1: " + value1);

        

    Assert.assertTrue(value1 == klass.value());

 

    Unsafe unsafe = getUnsafe();

    long valueOffset = unsafe.objectFieldOffset(field);

    System.out.println("value offset: " + valueOffset);

    int value2 = unsafe.getInt(klass, valueOffset);

    System.out.println("value2: " + value2);

        

    Assert.assertTrue(value1 == value2);

        

    long baseAddress = location(klass);

    System.out.println("base address: " + baseAddress);

    int value3 = unsafe.getInt(baseAddress + valueOffset);

    System.out.println("value3: " + value3);

    Assert.assertTrue(value1 == value3);

}

 

park/unpark

 

CAS操作

针对CAS操作提供了3个方法:compareAndSwapInt、compareAndSwapLong、compareAndSwapObject,分别用于原子操作更新Java变量,第1个用于int类型,第2个用于long类型,第3个用于Object类型。

Lock/Unlock

monitorEnter、monitorExit、tryMonitorEnter

monitorEnter用于加锁,monitorExit用于解锁。

 

 

创建实例但不初始化

allocateInstance

定义类

defineClass

有两种形式:

    /**
     * Tell the VM to define a class, without security checks.  By default, the
     * class loader and protection domain come from the caller's class.
     */
    public native Class defineClass(String name, byte[] b, int off, int len,
                                    ClassLoader loader,
                                    ProtectionDomain protectionDomain);
    /**
     * @deprecated Use defineClass(String, byte[], int, int, ClassLoader, ProtectionDomain)
     *             instead. This method will be removed in JDK 8.
     */
    @Deprecated
    @CallerSensitive
    public native Class defineClass(String name, byte[] b, int off, int len);

第2中方式已经废弃。

对象成员变量偏移量

 

类成员变量偏移量

和对象成员变量偏移量概念一样,一个是对象成员,一个是类成员。类在java中也是一个对象。

类成员变量基准地址

 

操作对象成员

 

操作对象成员(Volatile)

getObjectVolatile、putObjectVolatile

 

getIntVolatile、putIntVolatile、getBooleanVolatile、putBooleanVolatile、getByteVolatile、putByteVolatile、getShortVolatile、putShortVolatile、getCharVolatile、putCharVolatile、getLongVolatile、putLongVolatile、getFloatVolatile、putFloatVolatile、getDoubleVolatile、putDoubleVolatile

 

操作对象成员(Ordered/Lazy)

putOrderedObject、putOrderedInt、putOrderedLong

本地内存操作

setMemory、copyMemory

copyMemory有两种形式:

 

    /**
     * Sets all bytes in a given block of memory to a copy of another
     * block.
     *
     * <p>This method determines each block's base address by means of two parameters,
     * and so it provides (in effect) a <em>double-register</em> addressing mode,
     * as discussed in {@link #getInt(Object,long)}.  When the object reference is null,
     * the offset supplies an absolute base address.
     *
     * <p>The transfers are in coherent (atomic) units of a size determined
     * by the address and length parameters.  If the effective addresses and
     * length are all even modulo 8, the transfer takes place in 'long' units.
     * If the effective addresses and length are (resp.) even modulo 4 or 2,
     * the transfer takes place in units of 'int' or 'short'.
     */
    public native void copyMemory(Object srcBase, long srcOffset,
                                  Object destBase, long destOffset,
                                  long bytes);

 

 

    /**
     * Sets all bytes in a given block of memory to a copy of another
     * block.  This provides a <em>single-register</em> addressing mode,
     * as discussed in {@link #getInt(Object,long)}.
     *
     * Equivalent to <code>copyMemory(null, srcAddress, null, destAddress, bytes)</code>.
     */
    public void copyMemory(long srcAddress, long destAddress, long bytes) {
        copyMemory(null, srcAddress, null, destAddress, bytes);
    }
 

 

 

分配本地内存(native memory)

allocateMemory、reallocateMemory

 

释放本地内存(native memory)

freeMemory

对象成员偏移量操作

 

根据对象实际内存地址获取native指针(native pointer)

这里的实际内存地址就是Java对象在内存中的实际存储的地址,而这里的native指针(native pointer)指的是Java对象的一个native指针引用。

 

这就像C中:

 

A a;
A *ptr = &a;
上面的实际内存地址就相当于这里的a,native指针(native pointer)就相当于这里的ptr,它指向a,存放的是a的地址。

 

 

通过getAddress方法可以根据对象实际内存地址获取native指针(native pointer)。

 

另外还有个方法putAddress,该方法将一个native指针(native pointer)存入一个内存地址中。

 

throw

throwException

 

获取系统负载

getLoadAverage

Java Unsafe-如何得到Unsafe

 

Unsafe(sun.misc.Unsafe)是jdk中自带的一个类,因为是在sun.misc包下,所以一般也不建议直接使用,同时Unsafe提供了一组底层(low-level)、unsafe的操作。Unsafe类注释中也有这样一段描述:

写道
虽然该类及所有方法都是公开的,但使用该类是有限的,因为只有受信任的代码才能获得它的实例。

 

在Unsafe类中有个getUnsafe静态方法(public), 

 

@CallerSensitive
public static Unsafe getUnsafe() {
Class cc = Reflection.getCallerClass();
if (cc.getClassLoader() != null)
        throw new SecurityException("Unsafe");
    return theUnsafe;
}
 

 

注意这个方法上有个@CallerSensitive注解。

但如果使用这个方法来尝试得到Unsafe的话,恐怕不能直接如偿所愿了。该方法正常调用将返回错误。

@Test

publicvoid getUnsafe1() throws Throwable {

Unsafe unsafe = getUnsafe();

Assert.assertNotNull(unsafe);

}

错误信息如下:

java.lang.SecurityException: Unsafe

    at sun.misc.Unsafe.getUnsafe(Unsafe.java:68)

    at com.java.UnsafeTest.getUnsafe0(UnsafeTest.java:25)

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

    at java.lang.reflect.Method.invoke(Method.java:597)

    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)

    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)

    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)

    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)

    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)

    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)

    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)

    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)

    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)

    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)

    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)

    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)

    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)

    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)

    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)

    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)

    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)

    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

 

原因在与Unsafe类中getUnsafe方法被标注为@CallerSensitive,其中有如下一条代码:

Class cc = Reflection.getCallerClass();

它调用了Reflection类的getCallerClass()方法,Reflection类(sun.reflect.Reflection)在jdk\src\share\classes\sun\reflect目录下。该方法是个native方法:

@CallerSensitive

public static native Class getCallerClass();

对应的实现Reflection.c在jdk\src\share\native\sun\reflect目录下。该方法实现:

JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass

(JNIEnv *env, jclass unused)

{

    // Until there is hotspot @CallerSensitive support,

    // depth must always be 2 to get the immediate caller

    return JVM_GetCallerClass(env, 2);

}

这个方法直接调用了JVM_GetCallerClass方法,这里第二个参数表示深度(depth), 固定传值2表示得到直接调用者, 该方法实现jvm.cpp在hotspot\src\share\vm\prims目录下。该方法实现:

JVM_ENTRY(jclass, JVM_GetCallerClass(JNIEnv* env, int depth))

  JVMWrapper("JVM_GetCallerClass");

  klassOop k = thread->security_get_caller_class(depth);

  return (k == NULL) ? NULL : (jclass) JNIHandles::make_local(env, Klass::cast(k)->java_mirror());

JVM_END

 

Class classLoader:

Class类的classLoader字段,反射访问这个字段是被过滤掉的,所以通过reflection(反射)方式无法访问到这个字段。

1、Initialized in JVM not by private constructor

2、This field is filtered from reflection access, i.e. getDeclaredField will throw NoSuchFieldException

 

@org.junit.Test
public void getClassLoader() {
    Class klass = this.getClass();
    ClassLoader classLoader = klass.getClassLoader();
    Assert.assertNotNull(classLoader);

    Object field = null;
    try {
        field = field(klass, "classLoader");
        Assert.fail("fail");
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    Assert.assertNull(field);
}

 

如何得到Unsafe

 

可以通过反射的方式来访问Unsafe类中的theUnsafe静态成员变量,该theUnsafe静态成员变量在Unsafe第一次使用时就已经初始化。

private Unsafe getUnsafe() throws Throwable {

Class<?> unsafeClass = Unsafe.class;

for (Field f : unsafeClass.getDeclaredFields()) {

if ("theUnsafe".equals(f.getName())) {

f.setAccessible(true);

return (Unsafe) f.get(null);

}

}

thrownew IllegalAccessException("no declared field: theUnsafe");

}

 

@Test

publicvoid getUnsafe1() throws Throwable {

Unsafe unsafe = getUnsafe();

Assert.assertNotNull(unsafe);

}

另一种方式也是通过反射的方式调用私有构造方法

@Test

publicvoid getUnsafe2() throws Throwable {

Constructor<Unsafe> constructor = Unsafe.class.getDeclaredConstructor(new Class<?>[0]);

constructor.setAccessible(true);

Unsafe unsafe = constructor.newInstance(new Object[0]);

Assert.assertNotNull(unsafe);

}

由于在Unsafe第一次使用时就已经初始化创建了一个实例(Unsafe类中的theUnsafe静态成员变量),所以这种方式实际上又创建了一个实例。

 

 

 

Java Unsafe获取对象内存地址

 

public class UnsafeTestKlass {

 

    private int value;

   

    public UnsafeTestKlass() {

       this(99);

    }

   

    public UnsafeTestKlass(int value) {

       this.value = value;

    }

   

    public int value() {

       return value;

    }

}

获取对象内存地址

public long location(Object object) throws Throwable {

Unsafe unsafe = getUnsafe();

      

Object[] array = new Object[] {object};

 

long baseOffset = unsafe.arrayBaseOffset(Object[].class);

int addressSize = unsafe.addressSize();

long location;

switch (addressSize) {

case 4:

location = unsafe.getInt(array, baseOffset);

           break;

       case 8:

           location = unsafe.getLong(array, baseOffset);

           break;

       default:

           throw new Error("unsupported address size: " + addressSize);

    }

    return (location);

}

 

例子

@Test

public void getObjectAddress() throws Throwable {

    UnsafeTestKlass klass = new UnsafeTestKlass();

    long baseAddress = location(klass);

    System.out.println("base address: " + baseAddress);

}

 

 

 

关于Java Unsafe实现原理可参考另一篇文章:https://lobin.iteye.com/blog/2327452

0
3
分享到:
评论

相关推荐

    Java Unsafe类的使用.docx

    《Java Unsafe类的深入解析与应用》 Java的Unsafe类是一个强大的工具,它位于rt.jar包中,提供了原子级别的操作,这些操作都是通过JNI(Java Native Interface)直接调用本地C++库实现的。Unsafe的存在是为了应对高...

    Java Unsafe类1

    Java中的`Unsafe`类是一个非常特殊且强大的工具类,它提供了对Java内存模型的底层访问。这个类在`sun.misc`包下,由于其潜在的危险性和不稳定性,官方并不推荐直接使用,甚至在Java 9之后有计划移除部分功能。然而,...

    java Unsafe详细解析

    Unsafe为我们提供了访问底层的机制,这种机制仅供java核心类库使用,而不应该被普通用户使用。但是,为了更好地了解java的生态体系,我们应该去学习它,去了解它,不求深入到底层的C/C++代码,但求能了解它的基本...

    Java Unsafe类实现原理及测试代码

    Java中的`Unsafe`类是一个非常底层的工具类,它提供了对内存操作的直接访问,类似于C语言中的指针。由于其强大的能力,`Unsafe`类能够执行一些常规Java API无法完成的任务,但也正因为这种能力,它也可能带来安全...

    JDK8中sun.misc下UnSafe类源代码 UnSafe.java

    在Java编程中,sun.misc.UnSafe类是一个非常特殊的存在。这个类在JDK8中扮演着一个核心的角色,它提供了对Java语言规范中未公开的底层操作的访问。尽管UnSafe类并非设计为公共API的一部分,但它因其强大的功能而被...

    简单谈一谈Java中的Unsafe类

    Java中的`Unsafe`类是一个非常特殊且强大的工具,它允许开发者绕过Java的常规安全机制,直接进行底层的内存操作和线程控制。虽然官方不推荐在常规开发中使用,但`Unsafe`类在某些高性能和低延迟的应用场景中扮演着...

    UnsafeAdapter:一个工具包,用于协助使用Java Unsafe类来分配和管理本地堆外内存块

    Java的`Unsafe`类是Java语言中一个强大的工具,它提供了对内存的直接访问和控制,包括在堆外分配内存、执行无同步的字节码操作等。然而,由于其潜在的安全风险和易用性的缺乏,`Unsafe`通常被封装在高级库中供开发者...

    Unsafe_jdk1.5_rt.jar

    《深入理解Java Unsafe类在JDK 1.5中的应用》 在Java编程语言中,`Unsafe`类是一个特殊的存在,它提供了对内存操作的直接访问权限,绕过了Java的一些安全机制。在JDK 1.5版本的`rt.jar`库中,`Unsafe`类扮演着一个...

    一篇看懂Java中的Unsafe类

    Java中的`Unsafe`类是一个非常特殊的工具类,它位于`sun.misc`包下,不属于Java标准库的一部分。尽管如此,由于其强大的底层操作能力,它在许多高性能的Java框架和库中扮演着重要角色,例如Netty、Hadoop和Kafka。`...

    sun.misc.Unsafe源码

    《深入解析Java sun.misc.Unsafe》 在Java编程语言中,`sun.misc.Unsafe`类是一个神秘而强大的工具,它提供了对内存的直接操作和访问,绕过了Java的一些安全限制。这个类通常不被推荐在生产环境中直接使用,因为它...

    Java中unsafe操作实例总结

    Java中unsafe操作实例总结 Java中unsafe操作是Java无锁操作的基石,在无锁并发类中都少不了它们的身影,比如ConcurrentHashMap、ConcurrentLinkedQueue等都是由Unsafe类来实现的。Unsafe类提供了多种操作,包括...

    java魔法类:Unsafe应用

    java魔法类:Unsafe应用

    探秘Java并发:Atomic&amp;Unsafe的强大魔法

    本文深入解析Java并发编程中的两个关键类:Atomic和Unsafe。这些类在提高Java并发操作的效率和安全性方面扮演着至关重要的角色。原子操作的核心:原子操作是不可分割的操作单元,确保数据的一致性和完整性。Java通过...

    JDK Unsafe 源码注释

    虽然Oracle发行的JDK版本不包含Unsafe的源代码,但在并发编程中,Unsafe类为java.util.concurrent包里的类提供了底层支持,例如通过提供绕过JVM直接修改内存的能力和使用硬件CPU指令实现CAS(Compare-And-Swap)原子...

    unsafe:使用sun.misc.Unsafe的各种Java类

    unsafe-helper-包含一些简单的方法,这些方法使使用sun.misc.Unsafe更容易。 unsafe-collection-在ArrayList上建模的示例列表,该列表不存储对集合内对象的引用,而是直接将元素复制到列表中。 这有一些有趣的特性...

    Java并发编程之LockSupport、Unsafe详解.docx

    在Java并发编程中,LockSupport和Unsafe是两个关键的工具类,它们提供了底层的线程控制功能,使得开发者能够深入地管理和控制线程的行为。LockSupport是Java并发库中的一个核心工具类,它提供了线程的阻塞和唤醒功能...

    Unsafe.java

    JDK8中sun.misc下UnSafe类源代码 UnSafe.java

    java6.0源码-dsl-json:dsl-json

    java6.0源码DSL-JSON 库 最快的 ...UNSAFE/内部方法 POJO &lt;-&gt; 对象和/或数组格式 - 数组格式避免序列化名称,而对象格式可用于最小序列化模式 遗留名称映射 - 可以使用替代名称注释将多个版本的 JSO

    JDK8中sun.misc包下的UnSafe类

    JDK8中sun.misc包下的UnSafe类,想查看源码的就拿走,没积分的请与我联系!xtfggef@gmail.com

    Java中的魔法类:sun.misc.Unsafe示例详解

    Java中的`sun.misc.Unsafe`类是一个特殊的存在,它提供了对Java语言规范之外的底层操作的访问。这个类主要用于优化性能和实现一些JVM级别的功能,但同时也因为其潜在的安全风险和不稳定因素,通常不推荐在常规编程中...

Global site tag (gtag.js) - Google Analytics