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
- reflection
- module-info.java
module com.us { requires jdk.unsupported; }
/**
* 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-info.java
module com.us { }
- Compile
javac -d out/production/unsafe-api src/module-info.java src/com/us/UnsafeHolder.java --add-exports=java.base/jdk.internal.misc=com.us
- Run
java --add-exports=java.base/jdk.internal.misc=com.us -p out/production/unsafe-api/ -m com.us/com.us.UnsafeHolder
/**
*
* 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
- long objectFieldOffset(Field f)
unsafe.objectFieldOffset(UnsafeOffsetScaleApi.class.getDeclaredField("i"));
- long objectFieldOffset(Class<?> c, String name)
unsafe.objectFieldOffset(UnsafeOffsetScaleApi.class, "i");
- long staticFieldOffset(Field f)
unsafe.staticFieldOffset(UnsafeOffsetScaleApi.class.getDeclaredField("si"));
- Object staticFieldBase(Field f)
Object base = unsafe.staticFieldBase(UnsafeOffsetScaleApi.class.getDeclaredField("si")));
assert base == UnsafeOffsetScaleApi.class; //true
- int arrayBaseOffset(Class<?> arrayClass)
unsafe.arrayBaseOffset(byte[].class);
- int arrayIndexScale(Class<?> arrayClass)
assert unsafe.arrayIndexScale(byte[].class) == 1;
assert unsafe.arrayIndexScale(int[].class) == 4;
assert unsafe.arrayIndexScale(Object[].class) == 4;
assert unsafe.arrayIndexScale(long[].class) == 8;
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
- defineClass
byte[] classContent = new FileInputStream("...").readAllBytes();
Class clazz = unsafe.defineClass(null, classContent, 0, classContent.length, null, null);
- allocateInstance
UnsafeObject unsafeObject = (UnsafeObject) unsafe.allocateInstance(UnsafeObject.class);
assert unsafeObject.i == 0;
- allocateUninitializedArray
int[] ints = (int[]) unsafe.allocateUninitializedArray(Integer.TYPE, 5);
- throwException
unsafe.throwException(new Exception());
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
- 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)
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
- 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)
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
- putInt/putByte/putShort/putChar/putLong/putFloat/putDouble(address, value)
- getInt/getByte/getShort/getChar/getLong/getFloat/getDouble(address)
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
- allocateMemory(longbytes)
- 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)
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
- little-endian means the least significant byte(LSB) value is at the lowest address.
- big-endian means the most significant byte(MSB) value is at the lowest address.
Synchronization
park/unpark
Memory Barrier
loadFence / loadLoadFence
- Ensures that loads before the fence will not be reordered with loads and stores after the fence.
- A
LoadLoad
plusLoadStore
barrier. - C11 atomic_thread_fence(memory_order_acquire)(an "acquire fence").
storeFence / storeStoreFence
- Ensures that loads and stores before the fence will not be reordered with stores after the fence.
- A
StoreStore
plusLoadStore
barrier. - C11 atomic_thread_fence(memory_order_release)(a "release fence").
fullFence
- Ensures that loads and stores before the fence will not be reordered with loads and stores after the fence.
-
LoadLoad
plusLoadStore
plusStoreStore
plusStoreLoad
barrier. - C11 atomic_thread_fence(memory_order_seq_cst).
Unaligned Access
Integer/Short/Char/Long
- Define two short fields
private short s1 = 0x0102;
private short s2 = 0x0304;
-
Print all byte values from the two short fields
long offset = unsafe.objectFieldOffset(UnalignedAccess.class, "s1");
unsafe.getByte(obj, offset);//2
unsafe.getByte(obj, offset + 1);//1
unsafe.getByte(obj, offset + 2);//4
unsafe.getByte(obj, offset + 3);//3
-
Get unaligned short value
assert unsafe.getShortUnaligned(obj, offset + 1) == 0x0401;
网友评论