do we need unsafe in java?

57
Do we need Unsafe in Java? Andrei Pangin [email protected] il.ru

Upload: andrei-pangin

Post on 12-Feb-2017

2.179 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Do we need Unsafe in Java?

Do we need Unsafe in Java?

Andrei [email protected]

Page 2: Do we need Unsafe in Java?

Mystic sun.misc.Unsafe

Page 3: Do we need Unsafe in Java?

3

Can I override object with sun.misc.Unsafe?

Is there a way to force unload a classby using the sun.misc.Unsafe class?

Can one break a security manager with sun.misc.Unsafe?

Rescuing a swallowed Exception in Java

How to free memory using Java Unsafe, using a Java reference?

Create a mutable java.lang.String

Mystic sun.misc.Unsafe

Page 4: Do we need Unsafe in Java?

4 Mystic sun.misc.Unsafe

How to free memory using Java Unsafe, using a Java reference?

Player p = (Player) unsafe.allocateInstance(Player.class);

// Is there a way of accessing the memory address// from the object reference

unsafe.freeMemory(p.hashCode());

http://stackoverflow.com/questions/24429777

Page 5: Do we need Unsafe in Java?

5 Mystic sun.misc.Unsafe

Why it is called Unsafe

## A fatal error has been detected by the Java Runtime Environment:## SIGSEGV (0xb) at pc=0x00002ad221034ee5, pid=3680, tid=1091057984## JRE version: Java(TM) SE Runtime Environment (8.0_60-b27) (build 1.8.0_60-b27)# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.60-b23 mixed mode linux-amd64)# Problematic frame:# C [libc.so.6+0x6dee5] cfree+0x25## An error report file with more information is saved as:# /home/apangin/hs_err_pid3680.log#

Page 6: Do we need Unsafe in Java?

6

What is Unsafe actually

• Bridge between Class Library and JVM• For use inside JDK

- NIO- AWT- Reflection- java.util.concurrent- MethodHandles

• Exists in many JVMs, even on Android

Mystic sun.misc.Unsafe

Page 7: Do we need Unsafe in Java?

7 Mystic sun.misc.Unsafe

public final class Unsafe {

static { registerNatives(); sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); }

private Unsafe() {}

private static final Unsafe theUnsafe = new Unsafe();

@CallerSensitive public static Unsafe getUnsafe() { Class cc = Reflection.getCallerClass(); if (cc.getClassLoader() != null) throw new SecurityException("Unsafe"); return theUnsafe; }

Page 8: Do we need Unsafe in Java?

8 Mystic sun.misc.Unsafe

Getting Unsafe

public static Unsafe getUnsafe() throws Exception { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); return (Unsafe) f.get(null);}

Page 9: Do we need Unsafe in Java?

9

Security hole?

Security Manager is off by default

$ java -Djava.security.manager

java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun.misc")

Mystic sun.misc.Unsafe

Page 10: Do we need Unsafe in Java?

10 Mystic sun.misc.Unsafe

You’ve been warned!

$ javac Test.java

Test.java:2: warning: Unsafe is internal proprietary API and may be removed in a future releaseimport sun.misc.Unsafe; ^

$ javac -XDignore.symbol.file Test.java

Page 11: Do we need Unsafe in Java?

Inside Unsafe

Page 12: Do we need Unsafe in Java?

12 Inside Unsafe

public native long allocateMemory(long bytes);public native long reallocateMemory(long address, long bytes);public native void freeMemory(long address);

public native byte getByte(long address);public native void putByte(long address, byte x);

public native int getInt(Object o, long offset);public native void putInt(Object o, long offset, int x);

public native long objectFieldOffset(Field f);public native long staticFieldOffset(Field f);public native int arrayBaseOffset(Class<?> arrayClass);

public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);

Page 13: Do we need Unsafe in Java?

13

package snow.misc;

public class MyUnsafe {

public native int getInt(long address);

#include <jni.h>

JNIEXPORT jint JNICALLJava_snow_misc_MyUnsafe(JNIEnv* env, jobject myUnsafe, jlong address) { return *(jint*)address;}

Inside Unsafe

Page 14: Do we need Unsafe in Java?

14 Inside Unsafe

JNI call

1. Create stack frame2. Move arguments according to ABI3. Wrap objects into JNI handles4. Obtain JNIEnv* and jclass5. Trace method_entry6. Lock if synchronized7. Lazy lookup and linking8. in_java in_native thread transition9. Call the native function10. Check for safepoint11. Switch state to in_java12. Unlock if synchronized13. Notify method_exit14. Unwrap result, reset JNI handles block15. Handle exceptions16. Remove stack frame

Page 15: Do we need Unsafe in Java?

15

Implementation

• Most methods are JVM intrinsics- E.g. getInt is a single MOV instruction

• Executed in Java or VM context- Beware of mapped I/O

(safepoint pauses)

Inside Unsafe

Page 16: Do we need Unsafe in Java?

16

public native int getIntVolatile(Object o, long offset);public native void putIntVolatile(Object o, long offset, int x);public native void putOrderedInt(Object o, long offset, int x);

public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);

/* @since 1.8 */public native void loadFence();public native void storeFence();public native void fullFence();

public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, v + delta)); return v;}

Inside Unsafe

Page 17: Do we need Unsafe in Java?

17

i.getAndAdd(5)

lock addl $0x5,0xc(%r10)loop:mov 0xc(%r10),%eaxmov %eax,%r11dadd $0x5,%r11dlock cmpxchg

%r11d,0xc(%r10)sete %r11bmovzbl %r11b,%r11dtest %r11d,%r11dje loop

JDK 7u72 -XX:+PrintAssembly JDK 8u60

1 2 3 40

20406080

100120140

83

46

15 11

132

105

45 43

threads

ops

/ μs

Inside Unsafe

Page 18: Do we need Unsafe in Java?

18 Inside Unsafe

public native Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain);

public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches);

public native Object allocateInstance(Class<?> cls) throws InstantiationException;

public native void park(boolean isAbsolute, long time);public native void unpark(Object thread);

public native int getLoadAverage(double[] loadavg, int nelems);

public native void throwException(Throwable ee);

Page 19: Do we need Unsafe in Java?

19 Inside Unsafe

Deprecated in JDK 8, removed in 9

@Deprecatedpublic native void monitorEnter(Object o);

@Deprecatedpublic native void monitorExit(Object o);

@Deprecatedpublic native boolean tryMonitorEnter(Object o);

// Phantom HotSpot intrinsicspublic native void prefetchRead(Object o, long offset);public native void prefetchWrite(Object o, long offset);

Page 20: Do we need Unsafe in Java?

Use cases

Page 21: Do we need Unsafe in Java?

21

Off-heap collections

• Lists, sets, maps- Large capacity > 2 GB- Predictable GC pauses- No heap fragmentation (CMS Promotion Failures)- Data locality

Use cases

Page 22: Do we need Unsafe in Java?

22

Data locality

Key

ValueKey

Value

Map.Entry Off-heap layout

a b c a b c a b c

Use cases

Page 23: Do we need Unsafe in Java?

23 Use cases

Off-heap hash map

0 addr 0 … addr 0

hash time nextkey (?)

value

hash time 0key (?)

value

entry

one.nio.mem.SharedMemoryMap

Page 24: Do we need Unsafe in Java?

24 OffheapLongList

public OffheapLongList(int initialCapacity) { capacity = Math.max(initialCapacity, 4); base = unsafe.allocateMemory(capacity * 8L); }

public void add(long value) { if (size >= capacity) { capacity *= 2; base = unsafe.reallocateMemory(base, capacity * 8L); } unsafe.putLong(base + size * 8L, value); size++; }

public long get(int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException(); } return unsafe.getLong(base + index * 8L); }

Page 25: Do we need Unsafe in Java?

25 Use cases

When to free memory?

class OffheapCleaner<T> extends PhantomReference<T> { static final ReferenceQueue<T> queue = new ReferenceQueue<T>(); final long address;

OffheapCleaner(T referent, long address) { super(referent, queue); this.address = address; }}

while (true) { OffheapCleaner<T> cleaner = (OffheapCleaner<T>) queue.remove(); unsafe.freeMemory(cleaner.address);}

Page 26: Do we need Unsafe in Java?

26

Why not ByteBuffers?

• Size limit (Integer.MAX_VALUE)• Not thread-safe• No freeMemory

public void forceClean(ByteBuffer buffer) { ((sun.nio.ch.DirectBuffer) buffer)).cleaner().clean();}

Use cases

Page 27: Do we need Unsafe in Java?

27 sun.nio.ch.FileChannelImpl

try { // If no exception was thrown from map0, the address is valid addr = map0(imode, mapPosition, mapSize); } catch (OutOfMemoryError x) { // An OutOfMemoryError may indicate that we've exhausted memory // so force gc and re-attempt map System.gc(); try { Thread.sleep(100); } catch (InterruptedException y) { Thread.currentThread().interrupt(); } try { addr = map0(imode, mapPosition, mapSize); } catch (OutOfMemoryError y) { // After a second OOME, fail throw new IOException("Map failed", y); } }

Page 28: Do we need Unsafe in Java?

28 Cassandra

// Hoping GC will remove some not used tables.System.gc();

Thread.sleep(60000);

location = estimateFlushPath();

if (location!=null) return new File(location, ssTableFileName).getAbsolutePath();

// Hoping GC will remove some not used tables - sometimes 2 GC cycles are needed.logger_.warn("Still Insufficient disk space to flush "+ssTableFileName);System.gc();

Thread.sleep(60000);

location = estimateFlushPath();

Page 29: Do we need Unsafe in Java?

29 Use cases

Direct buffers ↔ Unsafe

Field addressField = Buffer.class.getDeclaredField("address");addressField.setAccessible(true);

// ByteBuffer addresslong address = addressField.getLong(byteBuffer);

// address ByteBufferByteBuffer result = prototype.duplicate();addressField.setLong(result, address);

Page 30: Do we need Unsafe in Java?

30 Use cases

Benchmark

Benchmark Mode Cnt Score Error Unitsb.byteBuffer thrpt 15 290,832 ± 7,858 ops/usb.rawMemory thrpt 15 480,799 ± 2,610 ops/us

public void byteBuffer() { buf.putLong(0, order.timestamp); buf.put(8, order.operationType); buf.putInt(9, order.productId); buf.putFloat(13, order.price);}

public void rawMemory() { unsafe.putLong(addr + 0, order.timestamp); unsafe.put(addr + 8, order.operationType); unsafe.putInt(addr + 9, order.productId); unsafe.putFloat(addr + 13, order.price);}

Page 31: Do we need Unsafe in Java?

31

I/O and persistence

• Persistent caches and storages- Memory-mapped files (64-bit)- Shared memory

• Cooperation with OS- Pointer arithmetic, alignment- mlock, madvise etc.

Use cases

Page 32: Do we need Unsafe in Java?

32 Use cases

Mapping large files

// MappingMethod map0 = FileChannelImpl.class.getDeclaredMethod( "map0", int.class, long.class, long.class);map0.setAccessible(true);long addr = (Long) map0.invoke(f.getChannel(), 1, 0L, f.length());

// UnmappingMethod unmap0 = FileChannelImpl.class.getDeclaredMethod( "unmap0", long.class, long.class);unmap0.setAccessible(true);unmap0.invoke(null, addr, length);

Page 33: Do we need Unsafe in Java?

33

IPC, Messaging

• Concurrent off-heap buffers and queues• High-performance messaging

- Disruptor- Aeron: 6M msg/s

• Shared data structures- Chronicle Map

Use cases

Page 34: Do we need Unsafe in Java?

34 Use cases

Coding / Decodingdo { v1 += getInt(buf, offset) * P2; v1 = ((v1 << 13) | (v1 >>> 19)) * P1;

v2 += getInt(buf, offset + 4) * P2; v2 = ((v2 << 13) | (v2 >>> 19)) * P1;

v3 += getInt(buf, offset + 8) * P2; v3 = ((v3 << 13) | (v3 >>> 19)) * P1;

v4 += getInt(buf, offset + 12) * P2; v4 = ((v4 << 13) | (v4 >>> 19)) * P1;} while ((offset += 16) <= limit);

public int getInt(byte[] buf, int off) { return (buf[off] & 0xff) | (buf[off + 1] & 0xff) << 8 | (buf[off + 2] & 0xff) << 16 | (buf[off + 3]) << 24;}public int getInt(byte[] buf, int off) { return unsafe.getInt(buf, byteArrayOffset + off);}

xxHash loop

Page 35: Do we need Unsafe in Java?

35 Use cases

BenchmarkBenchmark (length) Mode Cnt Score Error Unitsb.xxhashArray 10 thrpt 5 61697,875 ± 849,565 ops/msb.xxhashArray 100 thrpt 5 13552,417 ± 91,039 ops/msb.xxhashArray 1000 thrpt 5 1749,843 ± 12,290 ops/msb.xxhashUnsafe 10 thrpt 5 77358,056 ± 675,536 ops/msb.xxhashUnsafe 100 thrpt 5 34153,796 ± 319,798 ops/msb.xxhashUnsafe 1000 thrpt 5 5259,813 ± 43,870 ops/ms

Page 36: Do we need Unsafe in Java?

36

Serialization

• Fast conversion to/from byte[]• Access private fields

- Reflection vs. Unsafe• Instantiate objects without constructor

- unsafe.allocateInstance()

Use cases

Page 37: Do we need Unsafe in Java?

37

one-nio serialization

• Extend sun.reflect.MagicAccessorImpl- no bytecode verification

• Fast and compact• Supports class evolution

- Java serialization- JBoss- Kryo- Protobuf

Use cases

Page 38: Do we need Unsafe in Java?

38

Native APIs

• Own network library- Linux-specific TCP features and socket options- Integration with OpenSSL

• I/O and memory management- mlock- posix_fadvise

• setuid• sched_setaffinity

Use cases

Page 39: Do we need Unsafe in Java?

Removal of sun.misc.Unsafe

Page 40: Do we need Unsafe in Java?

40 Removal of sun.misc.Unsafe

An absolute disaster

Cassandra

Netty Guava

Hazelcast

Mockito

GWT

HadoopZookeeper

Kafka

Gson

Neo4j

Grails

Spring

Disruptor

JRuby

Scala

Akka

Page 41: Do we need Unsafe in Java?

41

Why?

Removal of sun.misc.Unsafe

Integrity and security

Maintenance costs

Page 42: Do we need Unsafe in Java?

42

Chronology

• JEP 200: The Modular JDK• Mark Reinhold speaks at Devoxx• Chris Engelbert started a discussion group• Apocalyptic post at blog.dripstat.com• JCrete • JVM Language Summit• JEP 260: Encapsulate Most Internal APIs

Removal of sun.misc.Unsafe

2014 / 07

2015 / 06

2015 / 07

2015 / 08

Page 43: Do we need Unsafe in Java?

43

Migration plan

• Replacement in JDK 8 hide in JDK 9- sun.misc.BASE64Encoder etc.- Available via command-line flag

• No replacement in JDK 8 available outside- sun.misc.Unsafe, sun.reflect.ReflectionFactory- sun.misc.Cleaner, sun.misc.SignalHandler

• Replacement in JDK 9 hide in JDK 9,

remove in JDK 10

Removal of sun.misc.Unsafe

Page 44: Do we need Unsafe in Java?

Replacements

Page 45: Do we need Unsafe in Java?

45

Project Panama

• JEP 191: Foreign Function Interface• Expected in Java 10• JNR

Replacements

public interface LibC { int setuid(@uid_t long uid);}

LibC libc = LibraryLoader.create(LibC.class).load("c");libc.setuid(restrictedUser);

Page 46: Do we need Unsafe in Java?

46

JEP 193: VarHandles

• Targeted for Java 9

Replacements

class Queue { int size; ...}

VarHandle queueSize = MethodHandles.lookup(). findVarHandle(Queue.class, "size", int.class);

queueSize.addAndGet(10);

Page 47: Do we need Unsafe in Java?

47 Replacements

// Desired syntaxVarHandle queueSize = Queue::size;

VarHandle intElementHandle = MethodHandles.lookup() .arrayElementVarHandle(int[].class);

VarHandle longArrayViewHandle = MethodHandles.lookup() .arrayElementViewHandle(byte[].class, long[].class, true, false);

ByteBuffer byteBuffer = ByteBuffer.allocateDirect(8);VarHandle bufferView = MethodHandles.lookup() .byteBufferViewVarHandle(long[].class, true, false);

Page 48: Do we need Unsafe in Java?

48 Replacements

public static void fullFence();public static void acquireFence()public static void releaseFence();public static void loadLoadFence();public static void storeStoreFence();

• getRelaxed, getVolatile, getOpaque• setRelaxed, setVolatile, setOpaque• getAquire, setRelease

• compareAndSet, compareAndExchangeVolatile• compareAndExchangeAcquire, compareAndExchangeRelease• weakCompareAndSet, weakCompareAndSetAcquire,

weakCompareAndSetRelease• getAndSet, getAndAdd, addAndGet

Page 49: Do we need Unsafe in Java?

49 Replacements

// Not in Java 9MemoryRegion region = MemoryRegion.allocateNative( "myname", MemoryRegion.UNALIGNED, Long.MAX_VALUE);

VarHandle regionView = region.asVarHandle(long[].class, true, false);

regionView.set(region, 0, Long.MAX_VALUE);return regionView.get(region, 0);

Page 50: Do we need Unsafe in Java?

50 Replacements

Serialization

ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();

Constructor<?> baseConstructor = Object.class.getDeclaredConstructor();

Constructor<?> constructor = reflectionFactory. newConstructorForSerialization(Foo.class, baseConstructor);

return (Foo) constructor.newInstance();

jobject AllocObject(JNIEnv *env, jclass clazz); JNI

Page 51: Do we need Unsafe in Java?

51 Replacements

Можно жить и без Unsafeно грустно

Page 52: Do we need Unsafe in Java?

Unsafe bugs

Page 53: Do we need Unsafe in Java?

53 Unsafe bugs

JVM Bugs

Вставка рисунка

## A fatal error has been detected by the Java Runtime Environment:## SIGSEGV (0xb) at pc=0x00002b9fd9f44898, pid=19692, tid=1096575296## JRE version: 6.0_24-b07# Java VM: Java HotSpot(TM) 64-Bit Server VM (19.1-b02 mixed mode linux-amd64)# Problematic frame:# J Test.loop(Lsun/misc/Unsafe;J)V## An error report file with more information is saved as:# /home/apangin/hs_err_pid19692.log## If you would like to submit a bug report, please visit:# http://java.sun.com/webapps/bugreport/crash.jsp#

for (int i = 0; i < BUF_SIZE; i += 8) unsafe.putLong(addr + i, Long.reverseBytes(i));

Page 54: Do we need Unsafe in Java?

54

JVM Bugs

• JDK-6968348: Unsafe + Long.reverseBytes• JDK-7196566: Reported by me • JDK-8022783: Non-public bug in C2• JDK-8087134: Wrong C1 optimization

Unsafe bugs

6u25

7u40

7u71

8u60

-XX:-TieredCompilation

Page 55: Do we need Unsafe in Java?

55 Unsafe bugs

Not yet fixed

RandomAccessFile raf = new RandomAccessFile("/dev/shm/cache.tmp", "rw");raf.setLength(5_000_000_000L);

MappedByteBuffer buf = raf.getChannel().map(READ_WRITE, 0, raf.length());for (int i = 0; i < 5000; i++) { buf.put(new byte[1_000_000]);} SIGBUS

Page 56: Do we need Unsafe in Java?

Thank you

@AndreiPangin

Page 57: Do we need Unsafe in Java?

57

Development @ OK

• Blog- http://habrahabr.ru/company/odnoklassniki

• Open source- https://github.com/odnoklassniki

• Career- http://v.ok.ru

Thank you