整理了几个曾经从网上记录sum.msic.Unsafe类的演示样例。供大家參考:
package com.fish.unsafe; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import org.junit.Before; import org.junit.Test; import sun.misc.Unsafe; /** * @version 1.0 * @author Fish */ public class UnsafeTest { public static Unsafe unsafe; @Before public void init() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { // 通过反射获取rt.jar下的Unsafe类 Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe) field.get(null); } /** * allocateInstance初始化对象不调用构造方法 * * @Description: * @throws InstantiationException * @throws IllegalAccessException * @author Fish * @date 2015年6月24日 */ @Test public void testAllocateInstance() throws InstantiationException, IllegalAccessException { UnsafeClass un = new UnsafeClass(); // constructor System.out.println(un.a()); // prints 1 UnsafeClass uu2 = UnsafeClass.class.newInstance(); // reflection System.out.println(uu2.a()); // prints 1 UnsafeClass uu3 = (UnsafeClass) unsafe.allocateInstance(UnsafeClass.class); // unsafe System.out.println(uu3.a());// prints 0 } /** * 改动private变量的值 * * @Description: * @throws NoSuchFieldException * @throws SecurityException * @author Fish * @date 2015年6月24日 */ @Test public void testObjectFieldOffset() { try { UnsafeClass un = new UnsafeClass(); System.out.println(un.isEqual()); Field f = un.getClass().getDeclaredField("a"); unsafe.putInt(un, unsafe.objectFieldOffset(f), 42); // memory System.out.println(un.isEqual()); // true, access granted } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 获取对象的大小 * @Description: * @author Fish * @date 2015年6月24日 */ @Test public void testSizeof() { UnsafeClass un = new UnsafeClass(); System.out.println(sizeOf1(un)); } public static long sizeOf1(Object object) { HashSet<Field> fields = new HashSet<Field>(); Class<?> c = object.getClass(); while (c != Object.class) { for (Field f : c.getDeclaredFields()) { if ((f.getModifiers() & Modifier.STATIC) == 0) { fields.add(f); } } c = c.getSuperclass(); } // get offset long maxSize = 0; for (Field f : fields) { long offset = unsafe.objectFieldOffset(f); if (offset > maxSize) { maxSize = offset; } } return ((maxSize / 8) + 1) * 8; // padding } /** * 浅拷贝:该方法能够用来拷贝不论什么类型的对象。动态计算它的大小。 * * @Description: * @author Fish * @date 2015年6月24日 */ @Test public void testShallowCopy() { List<String> list = new ArrayList<String>(); list.add("123A"); list.add("123B"); list.add("123C"); long size = sizeOf1(list); long start = toAddress(list); long address = unsafe.allocateMemory(size); unsafe.copyMemory(start, address, size); System.out.println(fromAddress(address)); } private static long normalize(int value) { if (value >= 0) return value; return (~0L >>> 32) & value; } public static long toAddress(Object obj) { Object[] array = new Object[] { obj }; long baseOffset = unsafe.arrayBaseOffset(Object[].class); return normalize(unsafe.getInt(array, baseOffset)); } static Object fromAddress(long address) { Object[] array = new Object[] { null }; long baseOffset = unsafe.arrayBaseOffset(Object[].class); unsafe.putLong(array, baseOffset, address); return array[0]; } /** * 密码隐藏:通常我们会将用完的密码设置为null,可是在设置为null到GC垃圾回收该对象,是有一定的时间。在这段时间内,该对象还存在于内存中。 * 就在这段时间内。非常可能被黑客利用 * * @Description: * @author Fish * @date 2015年6月24日 */ @Test public void testPassword() { String password = new String("l00k@myHor$e"); String fake = new String(password.replaceAll(".", "?")); System.out.println(password); // l00k@myHor$e System.out.println(fake); // ??
??????
?
?
?? unsafe.copyMemory(fake, 0L, null, toAddress(password), sizeOf1(password)); System.out.println(password); // ??
?????
???
?? System.out.println(fake); // ?????
?
??
???? } /** * 动态创建类 * @Description: * @author Fish * @date 2015年6月24日 */ @Test public void testDynamicClasses() { try { File f = new File("D:\A.class"); FileInputStream input = new FileInputStream(f); byte[] content = new byte[(int) f.length()]; input.read(content); input.close(); <span style="color:#FF0000;">// unsafe.defineClass(null, content, 0, content.length);该方法在JDK8找不到</span> Class<?
> c = unsafe.defineClass(null, content, 0, content.length); c.getMethod("a").invoke(c.newInstance(), null); // 1 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 大数组:这样的方式的内存分配不在堆上。且不受GC管理,所以必须小心Unsafe.freeMemory()的使用 * @Description: * @author Fish * @date 2015年6月24日 */ @Test public void testBigArray() { long SUPER_SIZE = (long) Integer.MAX_VALUE * 2; SuperArray array = new SuperArray(SUPER_SIZE); System.out.println("Array size:" + array.size()); // 4294967294 int sum = 0; for (int i = 0; i < 100; i++) { array.set((long) Integer.MAX_VALUE + i, (byte) 3); sum += array.get((long) Integer.MAX_VALUE + i); } System.out.println("Sum of 100 elements:" + sum); // 300 } } class SuperArray { private final static int BYTE = 1; private long size; private long address; public SuperArray(long size) { this.size = size; address = UnsafeTest.unsafe.allocateMemory(size * BYTE); } public void set(long i, byte value) { UnsafeTest.unsafe.putByte(address + i * BYTE, value); } public int get(long idx) { return UnsafeTest.unsafe.getByte(address + idx * BYTE); } public long size() { return size; } } class UnsafeClass { private long a; public UnsafeClass() { this.a = 1; } public long a() { return this.a; } public boolean isEqual() { return 42 == a; } }