jjug ccc 2013...
DESCRIPTION
JJUG CCC 2013 Fallで発表しました。TRANSCRIPT
JVMコードリーディング入門- JVMのOS抽象化レイヤーについて -
虎塚
November 9, 2013JJUG CCC 2013 Fall
R5-5
自己紹介
鳥形由希 (id: torazuka)(株)電通国際情報サービス勤務
http://twitter.com/torazukahttp://d.hatena.ne.jp/torazuka/
この入門セッションが生まれた経緯
皆さんなら何のテーマで入門セッションをしますか?
相談して題目をもらいました
JVMのソースコードについて話せばよいのでは?
ぎゃっぱぎゃっぱ
某上司
本当にありがとうございました.
メモリらへん
このセッションのテーマ
● JVM(Java Virtual Machine)を読む基本的な方法
● JVMのOS抽象化レイヤーの構成
○ 基本的な方法を使ってソースコードを読むと,
どんなことが分かるかを共有します
発表内容
1. JVMコードリーディング入門
1.1. ソースコードの入手からツールの選定まで
1.2. JVMソースコードの読み方
2. JVMのOS抽象化レイヤー
3. まとめ
対象のソースコード
OpenJDK(http://openjdk.java.net/)
OpenJDK
Oracle JDK7
78
8
JDK7のベース,Java7のOSS版
JDK8のベースになる予定
7u
JDK7のupdate
6JDK7のベース,Java6のOSS版 今回は7u
ソースコードの入手
● zipで取得する
○ メリット:入手が簡単、解凍すれば読める
○ デメリット:提供バージョンが固定の場合がある
● ソースコードリポジトリから取得する
○ メリット:好きなバージョンを入手できる
○ デメリット:読むまでに苦労する場合もある,
java.netが繋がりづらい
リポジトリからソースコードを入手する
sudo apt-get install mercurial
1. Mercurialをインストールする
2. hgforest-crewからforest.pyをダウンロードして任意の場所に置く
3. 設定ファイルhgrcにforest.pyを使う設定を追記
4. リポジトリからコードをcloneする
[extensions]forest={forest.pyを置いたディレクトリパス}/forest.py
hg clone http://hg.openjdk.java.net/jdk7u/jdk7u hgforest
(追記)下記手順の代わりにget_source.shを実行する方法もあります
ビルド
● デバッグ実行しながら動作を調べるなら必要○ ビルドツールの理解
○ 依存ライブラリの取得
○ 環境変数の設定
● 動かす前の調査としてコードを読むなら不要○ ビルドで生成されるソースコードがある場合は注意
OpenJDKのビルド方法は,README_builds.html参照
(参考)ビルドしようよ派
(略)次の理由でビルドすることを勧めます.
第一の理由は,ビルド処理の工程でソースファイル自体を生成することが
あるからです.(略)第二の理由は、Apacheのような巨大なソフトウェア特有
の事情です.(略)該当するソースコードがコンパイルされていない,つまり実
行ファイルに含まれてもいない,ことがあります.(略)最後の理由は,やや
気分的なものですが,そもそもビルドすら通せないソースでは,読むことは難
しいはずです.
(引用)WEB+DB PRESS Vol.69,p.133(松原克弥さん,井上誠一郎さん)
(参考)ビルドは最終手段派
gdb動作を調べる必要があるときに使います。
ただし、これは最終手段です。読んですぐに理解できるものなら実際に動か
して調べる必要はまったくありません。どうしてもわからないときに使いましょ
う。
よくわからないプロジェクトのビルドは面倒ですし、対象の関数を動かすのは
もっと面倒ですから。
(引用)ソースコードを読むときの3カ条(nariさん) http://d.hatena.ne.jp/authorNari/20111213/1323745618
ツール(1) エディタ
● C, C++ソースコードを扱い慣れているエディタ
○ Emacs, vi, 秀丸...お好きなエディタでどうぞ
● エディタが持っていて欲しい機能○ 正規表現が使える検索
○ ブックマーク
○ シンタックスハイライティング
ツール(2) エディタ続き
● サクラエディタ○ http://sakura-editor.sourceforge.net/○ for Windows(8にも対応)○ もし習熟したエディタがまだないならいいかも
● Eclipse IDE for C/C++ Developers○ http://www.eclipse.org/downloads/○ ただし,C, C++のコードを真っ当に読めるように
設定するのは大変…
ツール(3) エディタ以外
● 正規表現
○ ファイル内検索,キーワード抽出
● grep○ 正規表現と組み合わせて使うと便利
● ctags○ クラスや関数の定義にジャンプ
○ 同名のヘッダファイル/ソースコードにジャンプ
発表内容
1. JVMコードリーディング入門
1.1. ソースコードの入手からツールの選定まで
1.2. JVMソースコードの読み方
2. JVMのOS抽象化レイヤー
3. まとめ
ソースコードの読み方
1. 全体の階層構造を把握する
2. ファイルの関係を把握する
3. クラスの関係を把握する
何周も繰り返す
ポイント
● 分からなくても全部をざっくり何周も読む○ 実装の詳細や構文,テクニックに固執して止まらない
● メモをとったり図解したりする● 仮説と検証を繰り返す
○ 予想と実際の差分を見る○ 仮説で理解を橋渡しする
● 粒度を行き来して徐々に焦点を合わせる
ディレクトリ構造を見る(10%程度?)
ディレクトリ構造を読む(50%程度?)
ディレクトリ構造を理解する(100%)
コントラクトを見る(10%程度)
コントラクトを読む(50%程度?)
コントラクトを理解する(100%)
ロジックを見る(10%程度?)
ロジックを読む(50%程度?)
ロジックを理解する(100%)
1. 全体の階層構造を把握する
● ディレクトリ構成を見る● どんな名前空間があるか見る
● ファイルサイズの大きいものを把握する
● 抽象度の高い名前のファイルを把握する
2. ファイルの関係を把握する
● 中心的なファイルと周縁のファイルを推定する
○ 直接のinclude関係に着目して,図にしてみる
3.1. クラスの関係を把握する
● 他のクラスと関係性をたくさん持つクラスを把握する
● クラスと構造体をすべて抽出し,継承関係を図にする
3.2. C,C++レイヤーの切り分け
● クラスがどのレイヤーに属するかを見る
○ システムコールを行う層と、それを使う層
○ Cの構造体がC++のレイヤーに漏れないように
なっているはずなので、それを確かめる
● OSと接する末端を見つけ,
JVMとOSの境界を把握するOS
C
C++
「ざっくり読む」とは
● たとえばヘッダファイルだけをまず読む
● 役割と責任範囲に着目する
○ ヘッダコメントを読む
○ シグネチャに着目して読む
○ ファイルにどんなクラスがあるかを見る
○ クラスにどんなフィールドや関数があるかを見る
読む部分と読み飛ばしてもよい部分
● assert文 →読む
○ コントラクトなので非常に重要
● non-PRODUCTコード →読み飛ばしてもOK○ NOT_PRODUCT(code)のようなマクロ部分
ソースコードのコメントをどう読むか
● 実行できないので全幅の信頼は置けないが・・・
● ヘッダファイルのコメントは基本的に読む
○ 設計指針や専門用語の解説
● ソースファイルのコメントは次の場合に読む
○ 署名がついているもの
○ バグトラッカーの番号がついているもの
○ 新しい日付が書いてあるもの(OpenJDK正式リリース以降)※2011年7月28日
JVMの抽象クラスの特性
● 派生クラスがオーバーライドすべき関数を持つ
○ 純粋仮想関数
○ 直接インスタンス化できないように,new,
deleteの関数にエラー処理が書いてあることも
抽象クラス(余談)
gccなど特定のコンパイラでは,基底クラスを持つクラスは
(仮想関数やフィールドがなくても)バイナリが大きくなる.
そのため,クラス定義に基底クラスを直接書かずマクロにする.
そのようなコンパイラでコンパイルした時は,マクロが空文字列
に変換される.
c.f. hotspot/src/share/vm/memory/allocation.hpp
メモリ周りのコードによく出てくる略語
略語 フルスペル
oop ordinary object pointer
RO ResourceObj
TLAB thread local allocation buffers
BOT blockOffsetTable
発表内容
1. JVMコードリーディング入門
1.1. ソースコードの入手からツールの選定まで
1.2. JVMのソースコードをどう読むか
2. JVMのOS抽象化レイヤー
3. まとめ
読みたいところ
● OSからJVMがメモリを確保する部分
● OSから取得したメモリを管理する部分
OpenJDK7のディレクトリ構造 (抜粋)
dir名 中身 実装言語
corba CORBA API, rmic Java
hotspot コンパイラ,GC C++
jaxp JAXP API Java
jaxws JAXB, JAX-WS API Java
jdk コアライブラリ Java, C
langtools Compiler API Java
HotSpotのディレクトリ構造 (抜粋)
src/
os/
os_cpu/
cpu/
share/
linux/
solaris/
windows/
vm/
vm/
vm/
posix/ vm/
vm/
tools/ runtime/
memory/
他多数のディレクトリ
←OSごとの実装
JVM
今回まず読む部分 OS抽象化層
OS
OS抽象化層
メモリ管理
GC
アプリケーション
オブジェクト管理
ここ
os.cpp
OS抽象化層
Linux Windows Solaris
os_linux.hpp
os_windows.hpp
os_solaris.hpp
メモリ管理の機能
OS別のinclude#ifdef TARGET_OS_FAMILY_linux# include "os_linux.inline.hpp"# include "thread_linux.inline.hpp"#endif#ifdef TARGET_OS_FAMILY_solaris# include "os_solaris.inline.hpp"# include "thread_solaris.inline.hpp"#endif#ifdef TARGET_OS_FAMILY_windows# include "os_windows.inline.hpp"# include "thread_windows.inline.hpp"#endif
hotspot/src/share/vm/runtime/os.cpp#L51-62
OS別のinclude hotspot/src/share/vm/runtime/os.hpp#L33-41
#ifdef TARGET_OS_FAMILY_linux# include "jvm_linux.h"#endif#ifdef TARGET_OS_FAMILY_solaris# include "jvm_solaris.h"#endif#ifdef TARGET_OS_FAMILY_windows# include "jvm_windows.h"#endif
hotspot/src/os/{os_name}/vm/jvm_{os_name}.hをincludeする
os.hppに定義されたメンバー
● static関数が250個ほどある○ os_linux.hppは140個ほどオーバーライド○ os_windows.cppは150個ほどオーバーライド
● メモリ管理に関するもの,別の役割のもの
os::関数を呼び出すクラスの場所
asmc1classfilecodecompilergc_implementationinterpreterlibadt
memoryoopsoptoprimsruntimeservicessharkutilities
hotspot/src/share/vm/以下のディレクトリ
memory/以下で使われるos::関数
mallocfreenum_mallocsalloc_bytesfree_bytesreallocvm_allocation_granularity・・・・80箇所くらいで30種類くらい使われている
osクラスの一部
public:
static void init(void); // Called before command line parsing static jint init_2(void); // Called after command line parsing static void init_3(void); // Called at the end of vm init
hotspot/src/share/vm/runtime/os.hpp#L98-102
痺れる
次に読む部分 OS抽象化層の利用側
JVM
OS
OS抽象化層
メモリ管理
GC
アプリケーション
オブジェクト管理
ここ
memory/の中身
● 80ファイルくらい(hpp, cpp)● 抽象度の高いファイル名を持つもの
○ allocation○ heap○ space○ generation○ universe・・・
memory/のクラス継承関係
→画像
memory/のクラス継承関係
StackObjCHeapObjValueObjAllStatic
なんか大事なクラスっぽい
memory/のファイル
■赤=allocation.hpp■橙=赤ファイルを直接 includeするhpp■黄=橙ファイルを直接 includeするhpp
→画像
memory/のファイル(抜粋)
heap
generation
resourceArea
memRegionallocation
compactPermGen
permGen genOopClosures
cardTableRS
genCollectedHeap
barrierSetblockOffset
Table
generationSpec iterator
watermark
spacetenuredGeneration
sharedHeap
■赤=allocation.hppに 定義されたクラス
■橙=前頁の橙ファイルに 定義されたクラス
■黄=前頁の黄ファイルに 定義されたクラス
memory/のクラス継承関係(再)
→画像
allocation.hpp|cppの重要なクラス
クラス名 説明
CHeapObj Cヒープに配置されるオブジェクト用
StackObj スタックに配置されるオブジェクト用
ValueObj 組み込みオブジェクト用
ResourceObj リソースエリアに配置されるオブジェクト用
AllStatic 名前空間として使われるクラス用
CHeapObjの継承ツリー
space
resourceArea
generation
→画像
StackObjの継承ツリー
iterator
space
genOopClosures
→画像
ValueObjの継承ツリー
ResourceObjの継承ツリー
AllStaticの継承ツリー
発表内容
1. JVMコードリーディング入門
1.1. ソースコードの入手からツールの選定まで
1.2. JVMソースコードの読み方
2. JVMのOS抽象化レイヤー
3. まとめ
まとめ
こうやって読んでいけばいずれ分かる!!!● 分からなくても全部をざっくり何周も読む● メモをとったり図解したりする● 仮説と検証を繰り返す● 粒度を行き来して焦点を合わせる
ご清聴ありがとうございました.
参考資料
1. トップスタジオ,まつもとゆきひろ,平林俊一,鵜飼文敏:『Code Reading』,毎日コミュニケーションズ,2004.6.
2. 佐藤太一:「太一のコードの読み方メモ」,https://gist.github.com/taichi/2693387,2012.5.
3. 松原克弥,井上誠一郎:「C言語コードリーディング」,p.p.130-139,WEB+DB PRESS Vol.69,技術評論社,2012.6.
4. 中村成洋,相川光:『ガベージコレクションのアルゴリズムと実装』,秀和システム,2010.3.
5. 中村成洋:『徹底解剖「G1GC」実装編』,http://www.narihiro.info/g1gc-impl-book/,2013.5.
6. Alexey Ragozin:「Understanding GC pauses in JVM, HotSpot's minor GC.」,Grid Designer's Blog,2011.6.