«JMM в Android», Максим Ефимов, Redmadrobot
-
Upload
mailru-group -
Category
Software
-
view
6.476 -
download
4
Transcript of «JMM в Android», Максим Ефимов, Redmadrobot
О чем будем говорить?
• Зачем понадобилась JMM
• Happens-before
• Causality
• Dalvik MM vs JMM
• Dalvik bytecode vs JVM bytecode
1
Естественный порядок
2
int a, b; void foo() { int l1 = a; int l2 = l1 + 10; int l3 = b; int l4 = l2 % 3; }
3
Reordering
int a, b; void foo() { int l1 = a; int l3 = b; int l2 = l1 + 10; int l4 = l2 % 3; }
int a, b; void foo() { int l1 = a; int l2 = l1 + 10; int l3 = b; int l4 = l2 % 3; }
4
Reordering – ограничения
int a, b; void foo() { int l2 = l1 + 10; int l1 = a; int l3 = b; int l4 = l2 % 3; }
int a, b; void foo() { int l1 = a; int l2 = l1 + 10; int l3 = b; int l4 = l2 % 3; }
Reordering не меняет семантику кода водном потоке
Нотация записи
5
A==B==0
r1=AB=1
r2=BA=1
общее для обоих потоков
происходит в первом потоке происходит во втором потоке
r1=? r2=?
Reordering в многопоточности
6
A==B==0
r1=Ar2=B
B=1 A=1
Ожидаем (r1, r2) (0, 0),(1, 1),(0, 1)
A==B==0
r1=Ar2=B
A=1 B=1
Получаем (r1, r2) (0, 0),(1, 1),(0, 1),
(1, 0)
Семантика нарушается
Нужно больше порядка
7
Action 1.1
Action 1.2
Sync action 1
Sync action 2
Action 2.1
Action 2.2
Action 2.3Action 1.3
Action 1.4 Action 2.4
Поток 1 Поток 2
Порядок
междупотоками
Синхронизация
8
Monitor.Lock()
Action 1.2
Monitor.Unlock()
Monitor.Lock()
Action 2.1
Action 2.2
Action 2.3Action 1.3
Action 1.4 Monitor.Unlock()
Поток 1 Поток 2
Data race
9
• Один поток читает данные • Второй поток пишет данные • Эти два действия не синхронизированы
Итоги & QA - I
10
• Reordering оптимизирует код в одном потоке • Reordering ломает семантику многопоточного кода • Нужен порядок между действиями в разных потоках • Без синхронизации ломается семантика
Вопросы?
Базовые принципы
Java memory model
11
«A memory model describes, given a program and an execution trace of that program, whether the execution
trace is a legal execution of the program.»JSR 133
Sequential consistency
14
Action 1.1
Action 1.2
Action 2.1
Action 2.2
Action 2.3Action 1.2
Action 1.1
Action 1.2
Action 2.1
Action 2.2
Action 2.3Action 1.2
Вариант №1
Вариант №2
Happens before I
15
Monitor.unlock() Monitor.lock()HB
volatile write volatile readHB
Thread.start() 1st thread actionHB
last thread action Thread.terminate()HB
Thread.interrupt() interrupt detectedHB
default write 1st accessHB
constructor finalizerHB
HB пример
18
Monitor.Lock()
x = 1
Monitor.Unlock() Monitor.Lock()
b = xx = 3
Monitor.Unlock()
Поток 1 Поток 2
HBx = 2
b = ?
a = x a = ?
HB недостаточно
20
A==B==0
r1=A if(r1 != 0) B=1
r2=B if(r2 != 0) A=1
(r1, r2) = (0, 1)
r1=A B=1 if(r1 == 0) B=0
Causality
21
• Все действия группируются на коммиты • Коммиты выстраиваются в строгий порядок • Действие не может попасть в коммит, если это станет причиной состояния гонки
Causality - пример
22
A==B==0
r1=A B=1
r2=BA=r2
A==B==0B = 1
r2 = B
A = r2
r1 = A
A==B==0
r2 = B
A = r2
r1 = AB = 1
JVM vs DVM
25
Stack Register
Картинки из статьи https://markfaction.wordpress.com/2012/07/15/stack-based-vs-register-based-virtual-machine-architecture-and-the-dalvik-vm/
x86 vs ARM
28
• read\read • store\store • read\store • store\read
• read\read• store\store• read\store • store\read
ARM x86
No barriers II
30
A==B==false
A=truer1=B if(!r1) crit()
B=truer2=A
if(!r2) crit()
r1=B
A=true if(!r1) crit()
ARM address dependency
33
[A+8]==B==0
[A+8]=1 store/store B=16
loop: r0=B if(r0==0) goto loop r1 = 8 r2 = [A + r1]
ARM address dependency
34
[A+8]==B==0
[A+8]=1 store/store B=16
loop: r0=B if(r0==0) goto loop r1 = 8 + r0 r2 = [A + r1]
ARM AD limitation
35
A==B==0A = 1 loop_until(A==1)
B = 16loop: r0=B if(r0==0) goto loop r1 = 8 + r0 r2 = [A + r1]
Итоги & QA - III
36
DVM Memory model
• Есть большая зависимость от платформы • Есть адресная зависимость
Вопросы?
Bytecode
38
public foo(I)I L0 LINENUMBER 34 L0 ILOAD 1 BIPUSH 10 IADD ISTORE 2 L1 LINENUMBER 35 L1 ILOAD 2 IRETURN L2 LOCALVARIABLE this Lgenerator/android/TestJava; L0 L2 0 LOCALVARIABLE a I L0 L2 1 LOCALVARIABLE b I L1 L2 2 MAXSTACK = 2 MAXLOCALS = 3
.method public foo(I)I .registers 3 .param p1, "a" # I
.prologue .line 27 add-int/lit8 v0, p1, 0xa
.line 29 .local v0, "b":I return v0 .end method
JVM DVM
int a
int b
return b
b = a + 10int a
int breturn b
b = a + 10
Synchronized
39
public synchronized int foo(int a) { int b; b = a + 10; return b; }
public int foo(int a) { synchronized (this) { int b; b = a + 10; return b; }}
Bytecode synchronized method
40
public synchronized foo(I)I L0 LINENUMBER 34 L0 ILOAD 1 BIPUSH 10 IADD ISTORE 2 L1 LINENUMBER 35 L1 ILOAD 2 IRETURN L2 LOCALVARIABLE this Lgenerator/android/TestJava; L0 L2 0 LOCALVARIABLE a I L0 L2 1 LOCALVARIABLE b I L1 L2 2 MAXSTACK = 2 MAXLOCALS = 3
.method public declared-synchronized foo(I)I .registers 3 .param p1, "a" # I .prologue .line 21 monitor-enter p0 add-int/lit8 v0, p1, 0xa .line 22 .local v0, "b":I monitor-exit p0 return v0.end method
JVM DVM
b = a + 10
Synchronized block
41
public foo(I)I TRYCATCHBLOCK L0 L1 L2 null TRYCATCHBLOCK L2 L3 L2 null L4 LINENUMBER 10 L4 ALOAD 0 DUP ASTORE 2 MONITORENTER L0 //business logic L5 LINENUMBER 13 L5 ILOAD 3 ALOAD 2 MONITOREXIT L1 IRETURN L2 LINENUMBER 14 L2 FRAME FULL [generator/android/TestJava I java/lang/Object] [java/lang/Throwable] ASTORE 4 ALOAD 2 MONITOREXIT L3 ALOAD 4 ATHROW L6 LOCALVARIABLE b I L5 L2 3 LOCALVARIABLE this Lgenerator/android/TestJava; L4 L6 0 LOCALVARIABLE a I L4 L6 1 MAXSTACK = 2 MAXLOCALS = 5
.method public foo(I)I //initialization monitor-enter p0 //business logic :try_start_3 monitor-exit p0 return v0 .line 16 :catchall_5 move-exception v1 monitor-exit p0 :try_end_7 .catchall {:try_start_3 .. :try_end_7} :catchall_5 throw v1.end method
JVM DVM
Synchronized block – проще говоря
42
Monitor.enter() Throwable stored = null try{ businessLogic() } catch(Throwable e){ stored = e } Monitor.exit() if(stored != null) throw stored
return
JVM DVM
DVM synchronized method div
43
.method public final declared-synchronized fooDangerous(I)I .registers 4 .param p1, "a" # I .prologue .line 27 monitor-enter p0 :try_start_1 div-int/lit8 v0, p1, 0xa :try_end_3 .catchall {:try_start_1 .. :try_end_3} :catchall_5 .line 28 .local v0, "b":I monitor-exit p0 return v0 .line 27 .end local v0 # "b":I :catchall_5 move-exception v1 monitor-exit p0 throw v1.end method
.method public declared-synchronized foo(I)I .registers 3 .param p1, "a" # I .prologue .line 21 monitor-enter p0 add-int/lit8 v0, p1, 0xa .line 22 .local v0, "b":I monitor-exit p0 return v0.end method
b = a / 10b = a + 10
DMV synchronized method try-catch
44
• Вызов метода • Создание объекта • Деление целых чисел • Бросок исключения • Каст • Изменение поля класса • Загрузка класса
Итоги & QA - IV
45
• Байткод dalvik отличается от JVM • Не все флаги методов работают так же • Есть оптимизация в зависимости от опкодов
DVM bytecode
Links
46
• https://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf JSR 133
• http://shipilev.net/blog/2014/jmm-pragmatics/ Очень крутое объяснение JMM
• http://developer.android.com/intl/ru/training/articles/smp.html Гайд по MM в Android
• http://gee.cs.oswego.edu/dl/jmm/cookbook.html JMM для авторов компиляторов
• http://jcip.net/ Отличная книга про JMM