Unsafe–Java 指针(操作内存) java 8: rt.jar\sun.misc java 9: jdk.unsupported\sun.misc java.base\jdk.internal.misc
Java 8 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package sun.misc;public final class Unsafe { private static final Unsafe theUnsafe; .... public final native boolean compareAndSwapObject (Object var1, long var2, Object var4, Object var5) ; public final native boolean compareAndSwapInt (Object var1, long var2, int var4, int var5) ; public final native boolean compareAndSwapLong (Object var1, long var2, long var4, long var6) ; .... public static Unsafe getUnsafe () { Class var0 = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException ("Unsafe" ); } else { return theUnsafe; } } } VM.class public static boolean isSystemDomainLoader (ClassLoader var0) { return var0 == null ; }
获取Unsafe实例 1 2 3 4 5 6 7 8 9 10 11 12 private static Unsafe getUnsafe () { Unsafe unsafe = null ; try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe" ); theUnsafe.setAccessible(true ); unsafe = (Unsafe) theUnsafe.get(Unsafe.class); } catch (Exception e) { e.printStackTrace(); } finally { return unsafe; } }
修改内存
深入理解内存使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 static { long a = unsafe.allocateMemory(8 ); try { unsafe.putLong(a, 0x0102030405060708L ); byte b = unsafe.getByte(a); switch (b) { case 0x01 : byteOrder = ByteOrder.BIG_ENDIAN; break ; case 0x08 : byteOrder = ByteOrder.LITTLE_ENDIAN; break ; default : assert false ; byteOrder = null ; } } finally { unsafe.freeMemory(a); } }
类对象相关 putXXX(Object,offset,value); Object: 指向修改位置的起始地址 offset: 偏移 value: 待写入值
实例变量修改&类变量修改 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class People { private static int num; static { System.out.println("init class" ); } private int age; private People () { System.out.println("init People.instance" ); } public static int getNum () { return num; } public int getAge () { return age; } } Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe" );theUnsafe.setAccessible(true ); Unsafe unsafe = (Unsafe) theUnsafe.get(Unsafe.class);People user = (People) unsafe.allocateInstance(People.class);Field staticNumField = People.class.getDeclaredField("num" );staticNumField.setAccessible(true ); long staticNumFieldOffset=unsafe.staticFieldOffset(staticNumField);unsafe.putInt(People.class,staticNumFieldOffset,11 ); System.out.println(staticNumField.get(user)); Field field = People.class.getDeclaredField("age" );field.setAccessible(true ); long ageOffset = unsafe.objectFieldOffset(field);unsafe.putInt(user, ageOffset, 22 ); System.out.println(field.get(user)); unsafe.compareAndSwapInt(user,staticNumFieldOffset,11 ,111 ); System.out.println(staticNumField.get(user)); unsafe.compareAndSwapInt(People.class,staticNumFieldOffset,11 ,111 ); System.out.println(staticNumField.get(user));
结果
理解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 Unsafe unsafe = getUnsafe();final String s = "abc" ;String s1 = "abc" ;Field valueInString; try { valueInString = String.class.getDeclaredField("value" ); } catch (NoSuchFieldException e) { throw new RuntimeException (e); } long offset = unsafe.objectFieldOffset(valueInString);long base = unsafe.arrayBaseOffset(char [].class);long scale = unsafe.arrayIndexScale(char [].class);char [] values = (char []) unsafe.getObject(s, offset);unsafe.putChar(values, base + scale * 2 , 'd' ); System.out.printf("s:%s s1:%s s.equals(s1):%b\n" , s, s1, s.equals(s1)); System.out.println("s:" + s); System.out.printf("s:%s\n" , s); String s2 = "abc" ;String s3 = new String ("abc" );System.out.println("s:" + s + " s1:" + s1 + " s2:" + s2 + " s3:" + s3); System.out.printf("s:%s s1:%s s2:%s s3:%s\n" , s, s1, s2, s3); System.out.println("abc" );
结果:
1 2 3 4 5 6 s:abd s1:abd s.equals(s1):true s:abc s:abd s:abc s1:abd s2:abd s3:abd s:abd s1:abd s2:abd s3:abd abd
查看字节码文件:
1 2 3 System.out.println("s:abc s1:" + s1 + " s2:" + s2 + " s3:" + s3); System.out.printf("s:%s s1:%s s2:%s s3:%s\n" , "abc" , s1, s2, s3); System.out.println("abc" );
System.out.println final 常量已经被替换为 abc System.out.printf 通过引用关联到String类维护的字符串池…
Java 9 1 2 3 4 5 6 jdk.internal.misc.Unsafe; private static final Unsafe theUnsafe = new Unsafe ();public static Unsafe getUnsafe () { return theUnsafe; }
……