Unsafe: to be or to be removed?

Post on 15-Jan-2017

1,267 views 2 download

transcript

UnsafeandJava9/10АлексейФедоров,

Одноклассники/ JUG.ru@23derevo

2 @23derevo

Что такое Unsafe

• Оченьспециальныйобъект• СуществуетсJDK1.4 — уже15лет• НуженвClassLibrary,чтобыоттудадергать JVM

3 @23derevo

Что такое Unsafe

• Оченьспециальныйобъект• СуществуетсJDK1.4 — уже15лет• НуженвClassLibrary,чтобыоттудадергать JVM

“AVM/libraryinterface,designedstrictlyforusewithintheJDK”

MarkReinhold,JavaPlatformArchitectJVMLS2015

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(много!),MacOSXobjectiveCbridge

5 @23derevo

sun.misc.Unsafe

• Лежитвприватномпакетеsun.misc- раньшевSunJDK- потомвOpenJDK- перекочевалвOracleJDK

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();

@CallerSensitivepublic static Unsafe getUnsafe() {

Class cc = Reflection.getCallerClass();if (cc.getClassLoader() != null)

throw new SecurityException("Unsafe");return theUnsafe;

}

Как получить Unsafepublic 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 releaseimport sun.misc.Unsafe;

^

«Да мне пофиг!»

$ 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

ЧтоумеетUnsafe?

Demo1.AtomicInteger

package java.day.kiev;

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;

}

Create stack frameMove arguments according to ABI

Wrap objects into JNI handlesObtain JNIEnv* and jclass

Trace method_entryLock if synchronized

Lazy lookup and linkingin_java à in_native thread transition

Call the native functionCheck for safepoint

Switch state to in_javaUnlock if synchronized

Notify method_exitUnwrap result, reset JNI handles block

Handle exceptionsRemove stack frame

Сколько стоит JNI

Create stack frameMove arguments according to ABI

Wrap objects into JNI handlesObtain JNIEnv* and jclass

Trace method_entryLock if synchronized

Lazy lookup and linkingin_java à in_native thread transition

Call the native functionCheck for safepoint

Switch state to in_javaUnlock if synchronized

Notify method_exitUnwrap result, reset JNI handles block

Handle exceptionsRemove stack frame

Сколько стоит JNI

8+8

20 @23derevo

Intrinsics

• Большинствометодов— intrisics:- getInt —> mov- compareAndSwapInt —> cmpxchg

CASpublic 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),%eaxmov %eax,%r11dadd $0x5,%r11dlock cmpxchg %r11d,0xc(%r10)sete %r11bmovzbl %r11b,%r11dtest %r11d,%r11dje loop

JDK 7u72-XX:+PrintAssembly

AtomicInteger — i.getAndAdd(5)

loop:mov 0xc(%r10),%eaxmov %eax,%r11dadd $0x5,%r11dlock cmpxchg %r11d,0xc(%r10)sete %r11bmovzbl %r11b,%r11dtest %r11d,%r11dje loop

JDK 7u72 JDK 8u66

lock addl $0x5,0xc(%r10)

-XX:+PrintAssembly

AtomicInteger — i.getAndAdd(5)

loop:mov 0xc(%r10),%eaxmov %eax,%r11dadd $0x5,%r11dlock cmpxchg %r11d,0xc(%r10)sete %r11bmovzbl %r11b,%r11dtest %r11d,%r11dje loop

JDK 7u72 JDK 8u66

lock addl $0x5,0xc(%r10)

83

4615 11

132105

45 43

1 2 3 4

ops/μ

s

threads

-XX:+PrintAssembly

HowtofreememoryusingJavaUnsafe?

http://stackoverflow.com/questions/24429777

Demo2.freeMemory

27 @23derevo

hashCode (thanks to @AndreiPangin)

-XX:hashCode=n(http://habr.ru/post/165683/)• 0– Park-MillerRNG (поумолчанию)• 1– f(адрес,глобальное_состояние)• 2– константа1• 3– последовательныйсчетчик• 4– адресобъекта• 5– Thread-local Xorshift

Usecases

29 @23derevo

Off-heap Collections

• Lists,sets,maps- Largecapacity>2GB- PredictableGCpauses- Noheapfragmentation- Datalocality

Data locality

Key

ValueKey Value

Map.Entry Off-heaplayout

a b c a b c a b c

31 @23derevo

I/O and persistence

• Persistentcachesandstorages-Memory-mappedfiles(64-bit)- Sharedmemory

• CooperationwithOS- Pointerarithmetic,alignment- mlock,madvise etc.

32 @23derevo

IPC, Messaging

• Concurrentoff-heapbuffersandqueues• High-performancemessaging- Disruptor- Aeron:6Mmsg/s

• Shareddatastructures- ChronicleMap

УдалениеUnsafe

34 @23derevo

Тактика действий в случае удаления Unsafe

35 @23derevo

Тактика действий в случае удаления Unsafe

36 @23derevo

• Переписатькускикода- JNI- Reflection- NIO- etc.

Тактика действий в случае удаления Unsafe

37 @23derevo

• Переписатькускикода- JNI- Reflection- NIO- Etc.

• Какдействовать1. Новыйlayer:wrapper надUnsafe2. ЗаменитьнаwrapperнадpublicAPI

Тактика действий в случае удаления Unsafe

Беда1:PerformanceDegradation

Cassandra

Netty

Guava

Hazelcast

Mockito

GWT

HadoopZookeeper Kafka

Gson

Neo4j

Grails

Spring

Disruptor

JRuby

Scala

Akka

Unsafe

Cassandra

Netty

Guava

Hazelcast

Mockito

GWT

HadoopZookeeper 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 releaseimport sun.misc.Unsafe;

^

Слишкоммало евангелизма,Oracle!

Какразвиваласьситуация

45 @23derevo

Хронология событий

• JEP200:TheModularJDK- MarkReinholdвыступилна Devoxx 2014

• Постна blog.dripstat.com• ChrisEngelbert изHazelcast началдискуссию

46 @23derevo

Хронология событий

• JEP200:TheModularJDK- MarkReinholdвыступилна Devoxx 2014

• Постна blog.dripstat.com• ChrisEngelbert изHazelcast началдискуссию• ОбсуждениенаJCrete

47 @23derevo

Хронология событий

• JEP200:TheModularJDK- MarkReinholdвыступилна Devoxx 2014

• Постна blog.dripstat.com• ChrisEngelbert изHazelcast началдискуссию• ОбсуждениенаJCrete• MarkReinholdвыступилнаJVMLS• JEP260:EncapsulateMostInternalAPIs• JavaOne 2015— 5разъясняющихпрезентаций

48 @23derevo

План замены Unsafe на public API

• ReplacementinJDK8à hideinJDK9- sun.misc.BASE64Encoderetc.- Availableviacommand-lineflag

49 @23derevo

План замены Unsafe на public API

• ReplacementinJDK8à hideinJDK9- sun.misc.BASE64Encoderetc.- Availableviacommand-lineflag

• NoreplacementinJDK8à availableoutside- sun.misc.Unsafe,sun.reflect.ReflectionFactory- sun.misc.Cleaner,sun.misc.SignalHandler

50 @23derevo

План замены Unsafe на public API

• ReplacementinJDK8à hideinJDK9- sun.misc.BASE64Encoderetc.- Availableviacommand-lineflag

• NoreplacementinJDK8à availableoutside- sun.misc.Unsafe,sun.reflect.ReflectionFactory- sun.misc.Cleaner,sun.misc.SignalHandler

• ReplacementinJDK9à hideinJDK9,removeinJDK10

Чтоприходитназамену

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

Полезные материалы

• MarkReinhold@JVMLS2015- https://youtu.be/4HG0YQVy8UM

• PaulSandoz@JavaOne 2015- http://cr.openjdk.java.net/~psandoz/conferences/2015-JavaOne/j1-2015-unsafe-CON7076.pdf

• AndreiPangin @Joker2015- http://www.slideshare.net/AndreiPangin/do-we-need-unsafe-in-java

56 @23derevo

Development @ Одноклассники

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

• Opensource- https://github.com/odnoklassniki

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

БлагодарюАндреяПаньгина

@AndreiPangin

Вопросыиответы

Спасибозавнимание!

@23derevoalexey.fyodorov@corp.mail.ru