浅析Unsafe类

sun.misc.Unsafe类提供了像C语言那样直接操作内存的能力,Unsafe开辟的内存空间不占用heap空间,也不被GC回收

 1 private static final Unsafe theUnsafe;
 2 
 3 private Unsafe() {
 4 }
 5 
 6 @CallerSensitive
 7 public static Unsafe getUnsafe() {
 8     Class var0 = Reflection.getCallerClass();
 9     if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
10         throw new SecurityException("Unsafe");
11     } else {
12         return theUnsafe;
13     }
14 }

直接调用getUnsafe会过不了安全性检查

 1 package yuanma;
 2 
 3 import sun.misc.Unsafe;
 4 
 5 public class Test {
 6     public static void main(String[] args) {
 7         Unsafe unsafe = Unsafe.getUnsafe();
 8     }
 9 }
10 /*
11 Exception in thread "main" java.lang.SecurityException: Unsafe
12     at sun.misc.Unsafe.getUnsafe(Unsafe.java:90)
13     at yuanma.Test.main(Test.java:7)
14  */

可以通过修改-Xbootclasspath参数或者反射来获取Unsafe实例,正确的姿势是这样的

 1 package yuanma;
 2 
 3 import sun.misc.Unsafe;
 4 
 5 import java.lang.reflect.Field;
 6 
 7 public class Test {
 8     public static void main(String[] args) {
 9         try {
10             Field f = Unsafe.class.getDeclaredField("theUnsafe");
11             f.setAccessible(true);
12             Unsafe unsafe = (Unsafe) f.get(null);
13         } catch (Exception e) {
14             e.printStackTrace();
15         }
16     }
17 }

获取到Unsafe实例之后,就真的可以为所欲为了

1. 内存管理

allocateMemory(分配内存,不被GC回收需要手动free)、reallocateMemory(重新分配内存)、copyMemory(拷贝内存)、freeMemory(释放内存)

getAddress(获取内存地址)、addressSize、pageSize、getInt(获取内存地址指向的整数)、getIntVolatile(获取内存地址指向的整数并支持volatile语义)

putInt(将整数写入指定内存地址)、putIntVolatile(将整数写入指定内存地址并支持volatile语义)、putOrderedInt(将整数写入指定内存地址,有序或者有延迟的方法)

copyMemory无需对象实现clone方法即可拷贝对象(浅拷贝)

2. 非常规的对象实例化

allocateInstance方法直接生成对象实例,无需new或者反射获取对象——对象反序列化时不需要调用构造方法,能够重建和设置final字段

 1 package yuanma;
 2 
 3 import sun.misc.Unsafe;
 4 
 5 import java.lang.reflect.Field;
 6 
 7 public class Test {
 8     public static void main(String[] args) {
 9         try {
10             Field f = Unsafe.class.getDeclaredField("theUnsafe");
11             f.setAccessible(true);
12             Unsafe unsafe = (Unsafe) f.get(null);
13             Student student = (Student) unsafe.allocateInstance(Student.class);
14             student.setName("bin");
15             System.out.println(student.getName()); // bin
16         } catch (Exception e) {
17             e.printStackTrace();
18         }
19     }
20 
21     class Student {
22         String name;
23 
24         public String getName() {
25             return name;
26         }
27 
28         public void setName(String name) {
29             this.name = name;
30         }
31     }
32 }

3. 操作类、对象及变量

staticFieldOffset(静态域偏移)、defineClass(定义类)、defineAnonymousClass(定义匿名类)、ensureClassInitialized(确保类初始化)、objectFieldOffset(对象域偏移)

可以获取对象的指针,通过对指针进行偏移,不仅可以直接修改指针指向的数据(即使是私有的),甚至可以找到JVM已经认定为垃圾,可以回收的对象

4. 数组操作

arrayBaseOffset(获取数组第一个元素的偏移地址)+arrayIndexScale(获取数组中元素的增量地址)定位数组任意元素

由于Java数组最大长度为Integer.MAX_VALUE,而用Unsafe类的内存分配方法可以实现超大数组,实际上可以认为是C数组

 1 package yuanma;
 2 
 3 public class Test {
 4     public static void main(String[] args) {
 5         byte[] arr = new byte[Integer.MAX_VALUE + 1];
 6     }
 7 }
 8 /*
 9 Exception in thread "main" java.lang.NegativeArraySizeException
10     at yuanma.Test.main(Test.java:5)
11  */
 1 package yuanma;
 2 
 3 public class Test {
 4     public static void main(String[] args) {
 5         byte[] arr = new byte[Integer.MAX_VALUE];
 6     }
 7 }
 8 /*
 9 Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
10     at yuanma.Test.main(Test.java:5)
11  */

5. 线程同步

monitorEnter、tryMonitorEnter、monitorExit、compareAndSwapInt、compareAndSwap

6. 挂起与恢复

park、unpark——整个并发框架中对线程的挂起恢复操作被封装在LockSupport类中

7. 内存屏障

loadFence、storeFence、fullFence——用于定义内存屏障,避免代码重排序

 

posted @ 2018-08-20 11:22  sakura1027  阅读(201)  评论(0)    收藏  举报