Java Unsafe

2018-12-12  本文已影响0人  yunpxu

In java 11, there are sun.misc.Unsafe and jdk.internal.misc.Unsafe, and all methods in the first class are delegated to methods in the second class.

All source code is available at github.

Get an instance of Unsafe

sun.misc.Unsafe

/**
 * module com.us {
 *     requires jdk.unsupported;
 * }
 * @return
 */
public static sun.misc.Unsafe getSunMiscUnsafe() {
    sun.misc.Unsafe unsafe = null;
    try {
        Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
        unsafeField.setAccessible(true);
        unsafe = (sun.misc.Unsafe) unsafeField.get(null);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return unsafe;
}

jdk.internal.misc.Unsafe

/**
 *
 * module com.us {}
 * Compiler option --add-exports=java.base/jdk.internal.misc=com.us
 * VM option --add-exports=java.base/jdk.internal.misc=com.us
 * @return
 */
public static jdk.internal.misc.Unsafe getJdkMiscUnsafe() {
    return jdk.internal.misc.Unsafe.getUnsafe();
}

Heap Memory

Offset Scale Api

public class UnsafeOffsetScaleApi {
    private static Unsafe unsafe = Unsafe.getUnsafe();
    private int i;
    private static int si;
    /**
     * VM options --add-exports=java.base/jdk.internal.misc=com.us -enableassertions
     * @param args
     * @throws NoSuchFieldException
     */
    public static void main(String[] args) throws NoSuchFieldException {
        //field
        Field iField = UnsafeOffsetScaleApi.class.getDeclaredField("i");
        Field siField = UnsafeOffsetScaleApi.class.getDeclaredField("si");
        System.out.println(unsafe.objectFieldOffset(UnsafeOffsetScaleApi.class, "i"));
        System.out.println(unsafe.objectFieldOffset(iField));

System.out.println(unsafe.objectFieldOffset(UnsafeOffsetScaleApi.class, "si"));
        System.out.println(unsafe.staticFieldOffset(siField));
        System.out.println(unsafe.staticFieldBase(siField));

        System.out.println(unsafe.arrayBaseOffset(byte[].class));

        assert unsafe.arrayIndexScale(byte[].class) == 1;
        assert unsafe.arrayIndexScale(int[].class) == 4;
        assert unsafe.arrayIndexScale(Object[].class) == 4;
        assert unsafe.arrayIndexScale(long[].class) == 8;
    }
}

Object Array Exception Api

public class UnsafeObjectApi {
    private static Unsafe unsafe = Unsafe.getUnsafe();

    private int i;

    public UnsafeObjectApi() {
        i = 1;
    }

    /**
     * Exception is unchecked.
     */
    private static void throwExceptionUnchecked() {
        unsafe.throwException(new Exception());
    }

    /**
     * Exception is checked.
     */
    private static void throwException() {
        try {
            throw new Exception();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * VM options --add-exports=java.base/jdk.internal.misc=com.us -enableassertions
     * @param args
     * @throws Throwable
     */
    public static void main(String[] args) throws Throwable {
        byte[] byteContent = UnsafeObjectApi.class.getClassLoader().getResourceAsStream("com/us/UnsafeObjectApi.class").readAllBytes();
        Class clazz = unsafe.defineClass(null, byteContent, 0, byteContent.length, null, null);
        assert clazz.getName() == UnsafeObjectApi.class.getName();//true
        assert clazz != UnsafeObjectApi.class;//true

        UnsafeObjectApi unsafeObject = (UnsafeObjectApi) unsafe.allocateInstance(UnsafeObjectApi.class);
        assert unsafeObject.i == 0;

        int[] intArray = (int[]) unsafe.allocateUninitializedArray(Integer.TYPE, 5);

        throwExceptionUnchecked();
        throwException();

    }
}

put/get heap memory value

package com.us;

import jdk.internal.misc.Unsafe;

public class UnsafeJavaHeap {
    private static Unsafe unsafe = Unsafe.getUnsafe();

    //putGetMemory
    private byte i;

    //putInt/putObject/putBoolean/putByte/putShort/putChar/putLong/putFloat/putDouble/putAddress(object, offset, value)
    //getInt/getObject/getBoolean/getByte/getShort/getChar/getLong/getFloat/getDouble/getAddress(object, offset)
    private static void putGetMemory() {
        UnsafeJavaHeap object = new UnsafeJavaHeap();
        long iOffset = unsafe.objectFieldOffset(UnsafeJavaHeap.class, "i");
        byte value = 1;

        unsafe.putByte(object, iOffset, value);

        assert unsafe.getByte(object, iOffset) == value;
        assert object.i == value;
    }

    /**
     * VM options --add-exports=java.base/jdk.internal.misc=com.us -enableassertions
     *
     * @param args
     */
    public static void main(String[] args) {
        putGetMemory();
    }
}

putAddress issue

putAddress(object, offset, long value)
getAddress(object, offset)

package com.us;

import jdk.internal.misc.Unsafe;

public class UnsafePutAddress {

    private static Unsafe unsafe = Unsafe.getUnsafe();

    private byte b1;
    private byte b2;

    /**
     * VM options --add-exports=java.base/jdk.internal.misc=com.us -enableassertions
     * If you put a 2 bytes value(eg.256) to b1,
     * then the lower byte would be written to b1
     * and the higher byte would be written to b2(address next to b1)
     * @param args
     */
    public static void main(String[] args) {
        UnsafePutAddress object = new UnsafePutAddress();
        //Byte.MAX_VALUE  127(1 byte)  0111 1111
        //Byte.MIN_VALUE -128(1 byte)  1000 0000

        //                  long        byte1       byte2
        //  0111 1111       127         127        0
        //  1000 0000       128        -128        0
        //  1000 0001       129        -127        0
        //  1111 1111       255        -1          0
        //1 0000 0000       256         0          1
        //1 0000 0001       257         1          1
        long offset1 = unsafe.objectFieldOffset(UnsafePutAddress.class, "b1");
        long offset2 = unsafe.objectFieldOffset(UnsafePutAddress.class, "b2");
        //       b1          b2
        //0000 0000 | 0000 0000
        assert offset2 - offset1 == 1;

        unsafe.putAddress(object, offset1, 127);
        assert unsafe.getAddress(object, offset1) == 127;
        assert unsafe.getAddress(object, offset2) == 0;
        assert object.b1 == 127;
        assert object.b2 == 0;

        unsafe.putAddress(object, offset1, 128);
        assert unsafe.getAddress(object, offset1) == 128;
        assert unsafe.getAddress(object, offset2) == 0;
        assert object.b1 == -128;
        assert object.b2 == 0;

        unsafe.putAddress(object, offset1, 129);
        assert unsafe.getAddress(object, offset1) == 129;
        assert unsafe.getAddress(object, offset2) == 0;
        assert object.b1 == -127;
        assert object.b2 == 0;

        unsafe.putAddress(object, offset1, 255);
        assert unsafe.getAddress(object, offset1) == 255;
        assert unsafe.getAddress(object, offset2) == 0;
        assert object.b1 == -1;
        assert object.b2 == 0;

        unsafe.putAddress(object, offset1, 256);
        assert unsafe.getAddress(object, offset1) == 256;
        assert unsafe.getAddress(object, offset2) == 1;
        assert object.b1 == 0;
        assert object.b2 == 1;

        unsafe.putAddress(object, offset1, 257);
        assert unsafe.getAddress(object, offset1) == 257;
        assert unsafe.getAddress(object, offset2) == 1;
        assert object.b1 == 1;
        assert object.b2 == 1;
    }
}

set/copy/swap heap memory

package com.us;

import jdk.internal.misc.Unsafe;

public class UnsafeJavaHeap {
    private static Unsafe unsafe = Unsafe.getUnsafe();

    //setMemory
    private byte[] byteArray = new byte[4];
    private byte[] _byteArray = new byte[4];
    private short[] shortArray = new short[2];

    //setMemory(Object o, long offset, long byteArray, byte value)
    //copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long byteArray)
    //copySwapMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long byteArray, long elemSize)
    private static void setMemory() {
        UnsafeJavaHeap object = new UnsafeJavaHeap();
        byte value = 1;

        //set UnsafeJavaHeap.byteArray to [1,1,1,1]
        int size = object.byteArray.length;
        unsafe.setMemory(object.byteArray, Unsafe.ARRAY_BYTE_BASE_OFFSET, Unsafe.ARRAY_BYTE_INDEX_SCALE * size, value);
        for (int i = 0; i < size; i++) {
            assert object.byteArray[i] == value;
        }

        //copy UnsafeJavaHeap.byteArray[1,1,1,1] to UnsafeJavaHeap._byteArray [1,1,1,1]
        unsafe.copyMemory(object.byteArray, Unsafe.ARRAY_BYTE_BASE_OFFSET, object._byteArray, Unsafe.ARRAY_BYTE_BASE_OFFSET, Unsafe.ARRAY_BYTE_INDEX_SCALE * size);
        for (int i = 0; i < size; i++) {
            assert object._byteArray[i] == value;
        }

        //copy UnsafeJavaHeap.byteArray[1,1,1,1] to UnsafeJavaHeap.shortArray[257,257]
        //0000 0001, 0000 0001, 0000 0001, 0000 0001
        //0000 0001 0000 0001,  0000 0001 0000 0001
        size = object.shortArray.length;
        unsafe.copySwapMemory(object.byteArray, Unsafe.ARRAY_BYTE_BASE_OFFSET, object.shortArray, Unsafe.ARRAY_SHORT_BASE_OFFSET, Unsafe.ARRAY_SHORT_INDEX_SCALE * size, size);
        for (int i = 0; i < size; i++) {
            assert object.shortArray[i] == 257;
        }
    }

    /**
     * VM options --add-exports=java.base/jdk.internal.misc=com.us -enableassertions
     *
     * @param args
     */
    public static void main(String[] args) {
        setMemory();
    }
}

Direct Memory

put/get direct memory value

package com.us;

import jdk.internal.misc.Unsafe;

public class UnsafeDirectMemory {
    private static Unsafe unsafe = Unsafe.getUnsafe();

    //putInt/putByte/putShort/putChar/putLong/putFloat/putDouble(address, value)
    //getInt/getByte/getShort/getChar/getLong/getFloat/getDouble(address)
    private static void putGetMemory() {
        byte value = 1;
        //allocateMemory(long bytes)
        Long address = unsafe.allocateMemory(Byte.BYTES);

        unsafe.putByte(address, value);
        assert unsafe.getByte(address) == value;

        unsafe.putAddress(address, value);
        assert unsafe.getAddress(address) == value;

        //freeMemory
        unsafe.freeMemory(address);
    }

    /**
     * VM options --add-exports=java.base/jdk.internal.misc=com.us -enableassertions
     *
     * @param args
     */
    public static void main(String[] args) {
        putGetMemory();
    }
}

set/copy/swap direct memory

package com.us;

import jdk.internal.misc.Unsafe;

public class UnsafeDirectMemory {
    private static Unsafe unsafe = Unsafe.getUnsafe();

    //allocateMemory(long bytes)
    //reallocateMemory(long address, long bytes)
    //setMemory(long address, long bytes, byte value)
    //copyMemory(long srcAddress, long destAddress, long bytes)
    //copySwapMemory(long srcAddress, long destAddress, long bytes, long elemSize)
    //freeMemory(long address)
    private static void setMemory() {
        Long address1 = unsafe.allocateMemory(Byte.BYTES);
        address1 = unsafe.reallocateMemory(address1, Short.BYTES);

        unsafe.setMemory(address1, Short.BYTES, (byte) 1);//0x0101
        assert unsafe.getShort(address1) == 0x0101;

        Long address2 = unsafe.allocateMemory(Short.BYTES);
        unsafe.copyMemory(address1, address2, Short.BYTES);
        assert unsafe.getShort(address2) == 0x0101;

        Long address3 = unsafe.allocateMemory(Integer.BYTES);
        unsafe.copySwapMemory(address1, address3, Integer.BYTES, 4);
        assert unsafe.getInt(address3) == 0x01010000;

        unsafe.freeMemory(address1);
        unsafe.freeMemory(address2);
        unsafe.freeMemory(address3);
    }

    /**
     * VM options --add-exports=java.base/jdk.internal.misc=com.us -enableassertions
     *
     * @param args
     */
    public static void main(String[] args) {
        setMemory();
    }
}

System info

getLoadAverage

double[] loadAverages = new double[3];
unsafe.getLoadAverage(loadAverages,3);
Show the load average of the system over the last 1, 5, and 15 minutes.
[yunpxu@yunpxu-mac ~]$ uptime
21:26 up 10 days, 32 mins, 4 users, load averages: 1.42 1.78 1.98

addressSize

unsafe.addressSize();//8

pageSize

unsafe.pageSize();//4096

Endian

unsafe.isBigEndian();//false

Synchronization

park/unpark

Java LockSupport

Memory Barrier

loadFence / loadLoadFence

storeFence / storeStoreFence

fullFence

Unaligned Access

Integer/Short/Char/Long

unaligned value.png
上一篇 下一篇

猜你喜欢

热点阅读