Unsafe	and	Java	9/10
Алексей	Федоров,	
Одноклассники	/ JUG.ru
@23derevo
2 @23derevo
Что такое Unsafe
• Очень	специальный	объект
• Существует	с	JDK	1.4 — уже	15	лет
• Нужен	в	Class	Library,	чтобы	оттуда	дергать JVM
3 @23derevo
Что такое Unsafe
• Очень	специальный	объект
• Существует	с	JDK	1.4 — уже	15	лет
• Нужен	в	Class	Library,	чтобы	оттуда	дергать JVM
“A	VM/library	interface,	designed	
strictly	for	use	within	the	JDK”
Mark	Reinhold,	Java	Platform	Architect
JVMLS	2015
4 @23derevo
Используется в разных частях JDK
• 1.4 — Reflection,	Serialization,	NIO
• 1.5 — JSR166	(atomics,	locks),	CORBA,	AWT
• 6.0 — JSR166	(CopyOnWriteArrayList etc.)
• 7			 — JSR166	(ForkJoin etc.),	BigDecimal,	j.l.invoke
• 8					— JSR166	(много!),	Mac	OS	X	objective	C	bridge
5 @23derevo
sun.misc.Unsafe
• Лежит	в	приватном	пакете	sun.misc
- раньше	в	Sun	JDK
- потом	в	OpenJDK
- перекочевал	в	Oracle	JDK
6 @23derevo
А что на других JDK?
7 @23derevo
А что на других JDK?
public final class Unsafe {
static {
…
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;
}
Как получить Unsafe
public static final Unsafe UNSAFE = getUnsafe();
private static Unsafe getUnsafe() {
try {
Field f
= Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe) f.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
10 @23derevo
И всё???
По	умолчанию	Secutiry Manager	в	Java	выключен!
11 @23derevo
И всё???
$ java -Djava.security.manager
java.security.AccessControlException:
access denied ("java.lang.RuntimePermission"
"accessClassInPackage.sun.misc")
По	умолчанию	Secutiry Manager	в	Java	выключен!
«Тебя предупреждали»
$ javac Test.java
Test.java:2: warning: Unsafe is internal
proprietary API and may be removed in a
future release
import sun.misc.Unsafe;
^
«Да мне пофиг!»
$ javac Test.java
Test.java:2: warning: Unsafe is internal
proprietary API and may be removed in a
future release
import sun.misc.Unsafe;
^
$ javac -XDignore.symbol.file Test.java
Что	умеет	Unsafe?
Demo	1.	AtomicInteger
package java.day.kiev;
public class MyUnsafe {
public native int getInt(long address);
#include <jni.h>
JNIEXPORT jint JNICALL
Java_snow_misc_MyUnsafe(JNIEnv* env,
jobject myUnsafe, jlong address) {
return *(jint*)address;
}
Create stack frame
Move arguments according to ABI
Wrap objects into JNI handles
Obtain JNIEnv* and jclass
Trace method_entry
Lock if synchronized
Lazy lookup and linking
in_java à in_native thread transition
Call the native function
Check for safepoint
Switch state to in_java
Unlock if synchronized
Notify method_exit
Unwrap result, reset JNI handles block
Handle exceptions
Remove stack frame
Сколько стоит JNI
Create stack frame
Move arguments according to ABI
Wrap objects into JNI handles
Obtain JNIEnv* and jclass
Trace method_entry
Lock if synchronized
Lazy lookup and linking
in_java à in_native thread transition
Call the native function
Check for safepoint
Switch state to in_java
Unlock if synchronized
Notify method_exit
Unwrap result, reset JNI handles block
Handle exceptions
Remove stack frame
Сколько стоит JNI
8	+	8
20 @23derevo
Intrinsics
• Большинство	методов	— intrisics:
- getInt —> mov
- compareAndSwapInt —> cmpxchg
CAS
public final native boolean compareAndSwapInt(
Object o, long offset, int expected, int x);
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;
}
AtomicInteger — i.getAndAdd(5)
loop:
mov 0xc(%r10),%eax
mov %eax,%r11d
add $0x5,%r11d
lock cmpxchg %r11d,0xc(%r10)
sete %r11b
movzbl %r11b,%r11d
test %r11d,%r11d
je loop
JDK 7u72
-XX:+PrintAssembly
AtomicInteger — i.getAndAdd(5)
loop:
mov 0xc(%r10),%eax
mov %eax,%r11d
add $0x5,%r11d
lock cmpxchg %r11d,0xc(%r10)
sete %r11b
movzbl %r11b,%r11d
test %r11d,%r11d
je loop
JDK 7u72 JDK 8u66
lock addl $0x5,0xc(%r10)
-XX:+PrintAssembly
AtomicInteger — i.getAndAdd(5)
loop:
mov 0xc(%r10),%eax
mov %eax,%r11d
add $0x5,%r11d
lock cmpxchg %r11d,0xc(%r10)
sete %r11b
movzbl %r11b,%r11d
test %r11d,%r11d
je loop
JDK 7u72 JDK 8u66
lock addl $0x5,0xc(%r10)
83
46
15 11
132
105
45 43
1 2 3 4
ops	/	μs
threads
-XX:+PrintAssembly
How	to	free	memory	using	Java	Unsafe?
http://stackoverflow.com/questions/24429777
Demo	2.	freeMemory
27 @23derevo
hashCode (thanks to @AndreiPangin)
-XX:hashCode=n					(http://habr.ru/post/165683/)
• 0	– Park-Miller	RNG (по	умолчанию)
• 1	– f(адрес,	глобальное_состояние)
• 2	– константа	1
• 3	– последовательный	счетчик
• 4	– адрес	объекта
• 5	– Thread-local Xorshift
Use	cases
29 @23derevo
Off-heap Collections
• Lists,	sets,	maps
- Large	capacity	>	2	GB
- Predictable	GC	pauses
- No	heap	fragmentation	
- Data	locality
Data locality
Key
ValueKey
Value
Map.Entry Off-heap	layout
a b c a b c a b c
31 @23derevo
I/O and persistence
• Persistent	caches	and	storages
- Memory-mapped	files	(64-bit)
- Shared	memory
• Cooperation	with	OS
- Pointer	arithmetic,	alignment
- mlock,	madvise etc.
32 @23derevo
IPC, Messaging
• Concurrent	off-heap	buffers	and	queues
• High-performance	messaging
- Disruptor
- Aeron:	6M	msg/s
• Shared	data	structures
- Chronicle	Map
Удаление	Unsafe
34 @23derevo
Тактика действий в случае удаления Unsafe
35 @23derevo
Тактика действий в случае удаления Unsafe
36 @23derevo
• Переписать	куски	кода
- JNI
- Reflection
- NIO
- etc.
Тактика действий в случае удаления Unsafe
37 @23derevo
• Переписать	куски	кода
- JNI
- Reflection
- NIO
- Etc.
• Как	действовать
1. Новый	layer:	wrapper над	Unsafe
2. Заменить	на	wrapper	над	public	API
Тактика действий в случае удаления Unsafe
Беда	1:	Performance	Degradation
Cassandra
Netty
Guava
Hazelcast
Mockito
GWT
Hadoop
Zookeeper
Kafka
Gson
Neo4j
Grails
Spring
Disruptor
JRuby
Scala
Akka
Unsafe
Cassandra
Netty
Guava
Hazelcast
Mockito
GWT
Hadoop
Zookeeper
Kafka
Gson
Neo4j
Grails
Spring
Disruptor
JRuby
Scala
Akka
Беда	2:	Транзитивный	lock-in
42 @23derevo
Как так получилось?
$ javac Test.java
Test.java:2: warning: Unsafe is internal
proprietary API and may be removed in a future
release
import sun.misc.Unsafe;
^
Слишком	мало евангелизма,	Oracle!
Как	развивалась	ситуация
45 @23derevo
Хронология событий
• JEP	200:	The	Modular	JDK
- Mark	Reinhold	выступил	на Devoxx 2014
• Пост	на blog.dripstat.com
• Chris	Engelbert из	Hazelcast начал	дискуссию
46 @23derevo
Хронология событий
• JEP	200:	The	Modular	JDK
- Mark	Reinhold	выступил	на Devoxx 2014
• Пост	на blog.dripstat.com
• Chris	Engelbert из	Hazelcast начал	дискуссию
• Обсуждение	на	JCrete
47 @23derevo
Хронология событий
• JEP	200:	The	Modular	JDK
- Mark	Reinhold	выступил	на Devoxx 2014
• Пост	на blog.dripstat.com
• Chris	Engelbert из	Hazelcast начал	дискуссию
• Обсуждение	на	JCrete
• Mark	Reinhold	выступил	на	JVMLS
• JEP	260:	Encapsulate	Most	Internal	APIs
• JavaOne 2015	— 5	разъясняющих	презентаций
48 @23derevo
План замены Unsafe на public API
• Replacement	in	JDK	8	à hide	in	JDK	9
- sun.misc.BASE64Encoder	etc.
- Available	via	command-line	flag
49 @23derevo
План замены Unsafe на public API
• 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
50 @23derevo
План замены Unsafe на public API
• 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
Что	приходит	на	замену
JEP 193: VarHandles (Expected in Java 9)
class Queue {
int size;
...
}
VarHandle queueSize
= VarHandles.lookup().findFieldHandle(
Queue.class, "size", int.class);
queueSize.addAndGet(10);
53
• get, getVolatile, getAcquire, getOpaque
• set, setVolatile, setRelease, setOpaque
• compareAndSet, compareAndExchangeVolatile
• compareAndExchangeAcquire, compareAndExchangeRelease
• weakCompareAndSet, weakCompareAndSetAcquire,
weakCompareAndSetRelease
• getAndSet, getAndAdd, addAndGet
VarHandle handle = VarHandles.arrayElement(int[].class)
VarHandle viewH = VarHandles.arrayElementViewHandle(
byte[].class, long[].class, true);
54 @23derevo
Итоги
• Oracle	услышал	сообщество	и	изменил	планы
- Oracle	готов	и	дальше	слушать
- Сообщество	представляет	собой	силу,	
за	ним	экосистема
• Unsafe	все-таки	выпилят
- Но	постепенно,	в	течение	нескольких	лет
55 @23derevo
Полезные материалы
• Mark	Reinhold	@	JVMLS	2015
- https://youtu.be/4HG0YQVy8UM
• Paul	Sandoz	@	JavaOne 2015
- http://cr.openjdk.java.net/~psandoz/conferences
/2015-JavaOne/j1-2015-unsafe-CON7076.pdf
• Andrei	Pangin @	Joker	2015
- http://www.slideshare.net/AndreiPangin/do-we-
need-unsafe-in-java
56 @23derevo
Development @ Одноклассники
• Tech	Blog
- http://habrahabr.ru/company/odnoklassniki
• Open	source
- https://github.com/odnoklassniki
• Career
- http://v.ok.ru
Благодарю	Андрея	Паньгина
@AndreiPangin
Вопросы	и	ответы
Спасибо	за	внимание!
@23derevo
alexey.fyodorov@corp.mail.ru

Unsafe: to be or to be removed?