+ All Categories
Home > Documents > Jvm reading-synchronization

Jvm reading-synchronization

Date post: 30-Jun-2015
Category:
Upload: minoru-nakamura
View: 1,411 times
Download: 4 times
Share this document with a friend
22
Locking and Synchronization 第 7 第 JVM 第第第第第第第第第第第第第第 (OpenJDK) 第第 第 [email protected] [email protected] Twitter @nminoru_jp 1
Transcript
Page 1: Jvm reading-synchronization

Locking and Synchronization第 7 回 JVM ソースコードリーディングの会

(OpenJDK)

中村 実[email protected]

[email protected] @nminoru_jp

1

Page 2: Jvm reading-synchronization

Java のスレッド排他機構• Object はすべて同期オブジェクトになれる– Critical section 型の排他処理– 再帰的なロックも可能

• 文法– synchronized メソッド– Synchronized 文• バイトコードレベルでは monitorenter 、

monitorexit

– wait & notify

2

Page 3: Jvm reading-synchronization

Java Synchronization の問題点• 安易に書けるため使いすぎる– 不要な場所にも synchronized を書いてしまう。– 衝突しない synchronization が異常に多い。

3

class Hoge { int _hoge; public synchronized int getHoge() { return _hoge; } public synchronized void setHoge(int hoge) { _hoge = hoge; } }

Page 4: Jvm reading-synchronization

Java Synchronization の実装方法• 基本 (Biased Locking 以前 )– -XX:-UseBiasedLocking

• Biased Locking– -XX:+UseBiasedLocking(OpenJDK6 ではデフォル

ト )

4

Page 5: Jvm reading-synchronization

Hotspot の lock 関係のオプション

-XX:+UseBiasedLocking BiasedLocking を有効に。-XX:-TraceMonitorInflation Inflation/deflation 発生時にトレースを表示。-XX:-TraceBiasedLocking BaisedLocking に変更にトレースを表示。-XX:BiasedLockingStartupDelay=4000 VM 起動後に時間をおいてから biased locking

を有効化する。その待機時間をミリ秒で指定。-XX:BiasedLockingBulkRebiasThreshold=20 Threshold of number of revocations per type to

try to rebias all objects in the heap of that type-XX:BiasedLockingBulkRevokeThreshold=40 Threshold of number of revocations per type to

permanently revoke biases of all objects in the heap of that type

-XX:BiasedLockingDecayTime=25000 Decay time (in milliseconds) to re-enable bulk rebiasing of a type after previous bulk rebias

-XX:-PrintBiasedLockingStatistics Print statistics of biased locking in JVM

5

Page 6: Jvm reading-synchronization

基本ロック

6

Page 7: Jvm reading-synchronization

基本ロックの方針• 衝突しないロック (uncontened lock) を効率的

に処理する• Phase1 (Lightweight) Locked– Unlock 状態のオブジェクトに最初のスレッドが

ロックを行った状態。– Thread-local なデータ構造だけで対応。

• Phase2 Inflated– 第二以降のスレッドがロックを行い、 thread-

global なデータ構造に変更する。これを inflationと呼ぶ。

7

Page 8: Jvm reading-synchronization

ロックの構造体はどこにある?• oop の中にはない。• oop の第一ワードの _mark は多目的用途で、

ロック時には切り替える (markOop.hpp)

8

Fields

_klass

_mark hash code age 0 01

Pointer to basic lock 00

Pointer to monitor 10

Locked

Normal(unlocked)

Inflated lock

JavaThread* age 1 01 Biasedepoch

Page 9: Jvm reading-synchronization

Phase 1 • 最初のスレッドのロックは locked状態へ遷移

– Interpreter frame 上に BasicObjectLock を積むことでロックを表現– 元の _mark の内容を _displaced_header へ退避– _mark は BasicLock の位置を Comapre-And-Swap(CAS) で書き込む。

9

Fields

_klass

To basic lockBasicObjectLock

Object

_lock : BasicLock

_obj

_displaced_header

00BasicLock

Interpreter frame

Page 10: Jvm reading-synchronization

Phase 1

• 処理コード

• Recursive lock は?– Interpreter frame に複数の BasicObjectLock を積むことで実現。

• Unlock は– Stack unwind + α が unlock 処理。– ObjectSynchronizer::fast_exit

10

InterpreterRuntime::monitorenter in interpreterRuntime.cpp:585 ObjectSynchronizer::fast_enter in synchronizer.cpp:155 ObjectSynchronizer::slow_enter in synchronizer.cpp:201

Under src/share/vm/runtime/

Page 11: Jvm reading-synchronization

Phase2

11

Fields

_klass

To monitor _object

_header

_recursions

_owner

10

_cxq_cxq

_EntryList

ObjectMonitorObject

前にあった _mark を保存ロック対象の oop

ロックオーナーロックの再帰回数 ( 初回は 0)

_prev

_next

…_thread

ObjectWaiterOwning Thread

_prev

_next

…_thread

ObjectWaiter

Blocked Thread

Blocked Thread

Page 12: Jvm reading-synchronization

Phase2

• 処理コード– ObjectSynchronizer::inflate (inflation 処理 )– ObjectMonitor::enter (inflation 後のロック処理 )

• 複数のスレッドが同時に inflation を試みることがあるが、 object の _mark を CAS で書き換えることで衝突判定している。

• ObjectMonitor はスレッド毎に free list 管理されており inflate を実行しているスレッドが供出する。– ObjectSynchronizer::omAlloc

12

Page 13: Jvm reading-synchronization

Biased Locking

13

Page 14: Jvm reading-synchronization

Biased Locking のコンセプト• もっと CAS 命令の削除を– 基本ロックでは 1 回のロックで最低 1 回の CAS

命令を使う。• Biased Locking [Russell06]– あるスレッドからロックされたオブジェクトは、

また同じスレッドからロックされる傾向がある。– オブジェクトの中にスレッド情報を埋め込んで、

特定のスレッドに偏っている (biased) ことを示す。そのスレッドからのロックは CAS なしで済ませることが可能に。

14

Page 15: Jvm reading-synchronization

Biased Locking のコンセプト• どこに biased thread を挿れるのか?– hash code を潰す。

– hashcode のフィールドは初期値は 0 で、 hashが最初に呼ばれた時に動的に設定される。• hash() が呼ばれると biased は解ける。

15

hash code age 0 01 Normal(unlocked)

Thread id age 1 01 Biasedepoch

Page 16: Jvm reading-synchronization

Biased Locking のコンセプト• オブジェクト生成時は anonymously biased• 最初のスレッドがロックすると、そのスレッドの bias がかかる ( ここは CAS

が必要 )• Biased のかかったスレッドがロックする場合は _mark に変更が不要

– store-free- biased locking• ロックの衝突やその他が起きると bias をかけるのを止めて通常の状態に戻る。

– 以降、基本ロックを使用して元には戻らない。

16

0 1 01 T 1 01 … 0 01

anonymously biased biased toward given thread

… 0 00

bulk rebias

Initial lock

Revoke bias

Biasable Mode Normal Mode

Page 17: Jvm reading-synchronization

Store-free biased locking(SFBL)

17

BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { markOop mark = obj->mark(); if (mark->is_biased_anonymously() && !attempt_rebias) { // 初めてのロック } else if (mark->has_bias_pattern()) { Klass* k = Klass::cast(obj->klass()); markOop prototype_header = k->prototype_header(); if (!prototype_header->has_bias_pattern()) { // このクラスでは biased locking が許可されていない return BIAS_REVOKED; } else if (prototype_header->bias_epoch() != mark->bias_epoch()) { // epoch が一致しないので rebiased するか revoke する retrun } }

HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias); if (heuristics == HR_NOT_BIASED) { return NOT_BIASED; // biased lokcing に成功 }

Page 18: Jvm reading-synchronization

Bulk rebiasing and revocation

• Bulk rebiasing– どのスレッドで bias をかければいいのか時間

変化するので、一定周期で biased toward given thread を anonymously biased に戻す。

• Bulk revocation– ある種のオブジェクトは biased locking に向か

ない。

18

Page 19: Jvm reading-synchronization

もっと CAS 命令を減らしたい

19

Page 20: Jvm reading-synchronization

Synchronized getter は CAS を使わない

• Software Optimistic Lock Elision for Read-Only ciritical sections(SOLERO) [Nakaie10]– Object のヘッダにカウンタを用意– JIT を使って解析• オブジェクトのフィールドを変更する sync. method

は couner をアトミックに +1• オブジェクトのフィールドを変更しない sync.method

は counter 読む→フィールド読む→ counter 再読み込みする。• Counter が一致すれば成功。不一致なら通常の

synchronization 方式で再実行20

Counter bits xx

Page 21: Jvm reading-synchronization

Synchronized getter は CAS を使わない

21

class Hoge {

int _hoge; public synchronized int getHoge() { return _hoge; }

public synchronized void setHoge(int hoge) { _hoge = hoge; }

}

class Hoge { <<counter>> int _hoge; public synchronized int getHoge() { old = counter; ret = _hoge; if (old == counter) return ret; // 再実行 } public synchronized void setHoge(int hoge) { fetchadd counter +1 _hoge = hoge; }}

Page 22: Jvm reading-synchronization

参考文献• David Dice, “Implementing fast Java monitors with

relaxed locks”, In proceedings of the Java Virtual Machine, Research and Technology Symposium(JVM’01), April 2001, pp.79-90.

• Kenneth Russell and David Detlefs, “Eliminating Synchronization-Related Atomic Operations with Biased Locking and Bulk Rebiasing”, OOPSLA’06, pp.

• Takuya Nakaike and Maged M. Michael, “Lock Elision for Read-Only Critical Section in Java”, PLDI’10

22


Recommended