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——用于定义内存屏障,避免代码重排序