Unsafe:халявазакончилась?
АлексейФедоров,Одноклассники/ JUG.ru
2
Что такое Unsafe
• Оченьспециальныйобъект• СуществуетсJDK1.4 — уже15лет• НуженвClassLibrary,чтобыоттудадергать JVM
“AVM/libraryinterface,designedstrictlyforusewithintheJDK”
MarkReinhold,JavaPlatformArchitectJVMLS2015
3
Что такое Unsafe
• Оченьспециальныйобъект• СуществуетсJDK1.4 — уже15лет• НуженвClassLibrary,чтобыоттудадергать JVM
4
Используется в разных частях JDK
• 1.4— Reflection,Serialization,NIO• 1.5— JSR166(atomics,locks),CORBA,AWT• 6.0— JSR166(CopyOnWriteArrayList etc.)• 7 — JSR166(ForkJoin etc.),BigDecimal,java.lang.invoke• 8— JSR166(много!),MacOSXobjectiveCbridge
5
sun.misc.Unsafe
• Лежитвприватномпакетеsun.misc- раньшевSunJDK- потомвOpenJDK- перекочевалвOracleJDK
6
А что на других JDK?
7
А что на других JDK?
public final class Unsafe {
static {registerNatives();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;
}
9
Как получить 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
И всё???
ПоумолчаниюSecutiry ManagerвJavaвыключен!
11
И всё???
$ java -Djava.security.manager
java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun.misc")
ПоумолчаниюSecutiry ManagerвJavaвыключен!
12
«Тебя предупреждали»
$ javac Test.java
Test.java:2: warning: Unsafe is internal proprietary API and may be removed in a future releaseimport sun.misc.Unsafe;
^
13
«Да мне пофиг!»
$ 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?
package cee.secr.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;
}
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
18
Intrinsics
• Большинствометодов— intrisics:- getInt —> mov- compareAndSwapInt—> cmpxchg
CAS// nativepublic final native boolean compareAndSwapInt(
Object o, long offset, int expected, int x);
//non-nativepublic 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 JDK 8u66
lock addl $0x5,0xc(%r10)
83
4615 11
132105
45 43
1 2 3 4
ops/μ
s
threads
-XX:+PrintAssembly
Usecases
22
Off-heap Collections
• Lists,sets,maps- Largecapacity>2GB- PredictableGCpauses- Noheapfragmentation- Datalocality
23Data locality
Key
ValueKey
Value
Map.Entry Off-heaplayout
a b c a b c a b c
24
I/O and persistence
• Persistentcachesandstorages- Memory-mappedfiles(64-bit)- Sharedmemory
• CooperationwithOS- Pointerarithmetic,alignment- mlock,madvise etc.
25
IPC, Messaging
• Concurrentoff-heapbuffersandqueues• High-performancemessaging- Disruptor- Aeron:6Mmsg/s
• Shareddatastructures- ChronicleMap
УдалениеUnsafe
27
Тактика действий в случие удаления Unsafe
• Переписатькускикода- JNI- Reflection- NIO- etc.
28
Тактика действий в случие удаления Unsafe
• Переписатькускикода- JNI- Reflection- NIO- etc.
• Какдействовать1. Новыйlayer:wrapper надUnsafe2. ЗаменитьнаwrapperнадpublicAPI
Беда1:PerformanceDegradation
Cassandra
Netty
Guava
Hazlecast
Mockito
GWT
HadoopZookeeper
Kafka
Gson
Neo4j
Grails
Spring
Disruptor
JRuby
Scala
Akka
Cassandra
Netty
Guava
Hazlecast
Mockito
GWT
HadoopZookeeper
Kafka
Gson
Neo4j
Grails
Spring
JRuby
Scala
Akka
UnsafeDisruptor
Беда2:Transitivelock-in
33
Как так получилось?
$ javac Test.java
Test.java:2: warning: Unsafe is internal proprietary API and may be removed in a future releaseimport sun.misc.Unsafe;
^
34
Как так получилось?
Слишкоммалоевангелизма,Oracle!
$ javac Test.java
Test.java:2: warning: Unsafe is internal proprietary API and may be removed in a future releaseimport sun.misc.Unsafe;
^
Какразвиваласьситуация
36
Хронология событий
• JEP200:TheModularJDK
37
Хронология событий
• JEP200:TheModularJDK- MarkReinholdвыступилна Devoxx 2014
38
Хронология событий
• JEP200:TheModularJDK- MarkReinholdвыступилна Devoxx 2014
• Постна blog.dripstat.com
39
Хронология событий
• JEP200:TheModularJDK- MarkReinholdвыступилна Devoxx 2014
• Постна blog.dripstat.com• ChrisEngelbert изHazelcast началдискуссию
40
Хронология событий
• JEP200:TheModularJDK- MarkReinholdвыступилна Devoxx 2014
• Постна blog.dripstat.com• ChrisEngelbert изHazelcast началдискуссию• ОбсуждениенаJСrete
41
Хронология событий
• JEP200:TheModularJDK- MarkReinholdвыступилна Devoxx 2014
• Постна blog.dripstat.com• ChrisEngelbert изHazelcast началдискуссию• ОбсуждениенаJCrete• MarkReinholdвыступилнаJVMLS- всенемногоуспокоились
42
Хронология событий
• JEP200:TheModularJDK- MarkReinholdвыступилна Devoxx 2014
• Постна blog.dripstat.com• ChrisEngelbert изHazelcast началдискуссию• ОбсуждениенаJCrete• MarkReinholdвыступилнаJVMLS- всенемногоуспокоились
• JEP260:EncapsulateMostInternalAPIs
43
План замены 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
Чтоприходитназамену
JEP193:VarHandlesExpectedinJava9
class Queue {int size;...
}
VarHandle queueSize = VarHandles.lookup().findFieldHandle(Queue.class, "size", int.class);
queueSize.addAndGet(10);
46
• 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 viewHandle = VarHandles.arrayElementViewHandle(byte[].class, long[].class, true);
47
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(8);VarHandle bufferView =
VarHandles.byteBufferViewHandle(long[].class, true);
MemoryRegion region = MemoryRegion.allocateNative("myname", MemoryRegion.UNALIGNED, Long.MAX_VALUE);
VarHandle regionView =VarHandles.memoryRegionViewHandle(long[].class, true);
regionView.set(region, 0, Long.MAX_VALUE);return regionView.get(region, 0);
48
Итоги
• Вендор услышалсообществоиизменилпланы- Вендор готовидальшеслушать- Сообществопредставляетсобойсилу,занимэкосистема
49
Итоги
• Вендор услышалсообществоиизменилпланы- Вендор готовидальшеслушать- Сообществопредставляетсобойсилу,занимэкосистема
• Unsafeвсе-такивыпилят- Нопостепенно,втечениенесколькихлет
50
Development @ Одноклассники
• TechBlog- http://habrahabr.ru/company/odnoklassniki
• Opensource- https://github.com/odnoklassniki
• Career- http://v.ok.ru
БлагодарюАндреяПаньгина
@AndreyPangin
Вопросыиответы