Upload
masaya-tarui
View
2.775
Download
0
Embed Size (px)
Citation preview
自己紹介
• 樽家昌也 (Masaya TARUI)
• twitter id: @taru
• ircnet: tal_
• freenode: tarui
• 平日はふつうに?サラリーマン。
• 年に1,2度、networkと無縁な生活を求めて旅に
• 仕事で直接Rubyが対象になることは今のところない
• Rubyを使い始めてから13年目ぐらい?
これまで
1. Rubyを使い始める
2. よくわからない不具合はRubyレベルのWorkaroundで適当にごまかす
3. メモリリークとかSEGVに泣かされる
4. 仕方がなく、Cコードに手を入れる
5. Rubyの独特な構成が面白くてCコードに手を入れる ←Now!!
今日の対象者・・・
『NKT77さん「Hadoop with Ruby-僕がPythonを選んだ理由」』
『初心者からコミッターまで、更にPythonistaやらC#erなど幅広い言語
経験を元に、日頃のふとした疑問や事例を紹介できたらとおもいます。』
Σ(゚д゚;)
どうやらawayらしい。。。
.rbなのに、おかしくね?
(http://kawasakirb.doorkeeper.jpから引用)
メモリアロケーションからみた
拡張ライブラリに大切なことアジェンダ
• 拡張ライブラリ書き方復習
• Ruby のGC
• 拡張ライブラリ by C++ 準備不足によりキャンセルホントウニスイマセン
• おまけ:最近のGC事情
拡張ライブラリ
• RubyにC言語など他言語で書かれたプログラムをリンクさせて動かす仕組み
• Rubyは拡張ライブラリが書きやすい言語と言われている [誰]
•プロトタイピングをPure Rubyで行ってその後不満があれば拡張ライブラリを書けばいいと思います!
はじめての拡張ライブラリ
1. Cコードを用意する
2. ruby –r mkmf –e ”create_makefile(’sample’)”
3. make
4. ruby –r ./sample –e”p JUST_CLASS”
5. 出来上がり
サンプルライブラリAYB
• 全ての基地を頂くライブラリ
• AYBのオブジェクトのbelong_toメ
ソッドに文字列を渡すと、その中のbaseをXXXXと塗りつぶして最後に”All your base are belong to us”とのたまってくれます
• C拡張ライブラリなのに中でsplitとかconcatとか呼んでますが今回は気にしないでください・・・
• “base”で分割してforループで”XXXX”つけて最後だけ特別なメッセージを付ける
悪いところ
RubyのGCってmark&sweepだから保守的でmark漏れな
んて起こらないんじゃないの!?
大体この辺が悪くて、利用中のデータがGarbage Correct されてしまっている
Arrayの中身を走査している最中にArrayが消されてお亡くなりに。
※こんな恣意的なコードになったのはなかなかチェックから漏れなかったから・・・
ここで、あまり世間で聞かない話をひとつ
• RubyのGCはRubyオブジェクトの先頭に対してしか調査をしない!
• ArrayとかStringの大きな配列はGCで管理されていない領域に確保される。
(多分、もう当たり前すぎてだれも言及しない…のか?)
RubyObject
ただ単にmallocで
確保された領域
保護対象ここだけ
RARRAY_PTR
どうしてmark漏れが発生し、Rubyが落ちるのか
RubyObject
ただ単にmallocで
確保された領域
保護対象ここだけ
RARRAY_PTR
1. RARRAY_PTRで配列の先頭アドレスをもらう
2. もうこちらのアドレスは使わないので、レジスタorスタックは再利用可能!
4. このオブジェクトは使われてないと判断。オブジェクトに関係するものをRARRAY_PTR先も含めて全部回収。
3. GC発生
5. RARRAY_PTR先の内容が壊れる
Why?
RubyObject
normal
• 単純に言えば効率のため
RubyObject
RubyObject
RubyObject
normal normal
normal
normal
normal
小さい固定長
heaps_slot
名前すらない?malloced memory?
こちらの領域のデータが何を意味するかはRubyObjectが管理
こちらのアドレスに関係するデータだけを見ればいい固定長なので簡単に枝切可能
対処方法
RubyObject
ただ単にmallocで
確保された領域
保護対象ここだけ
RARRAY_PTR
1. RARRAY_PTRで配列の先頭アドレスをもらう
2. もうこちらのアドレスは使わないので、レジスタorスタックは再利用可能!
4. このオブジェクトは使われてないと判断。オブジェクトに関係するものをRARRAY_PTR先も含めて全部回収。
3. GC発生
5. RARRAY_PTR先の内容が壊れる
ちょっと待った!!
RB_GC_GUARD() とは
•そこに広がっているのは黒魔術。余人は決して手を出してはいけない。。。
• 正直、何をしているのかよくわからない
• コンパイラに値をスタックに残しておくように出せる指示はない
• いつコンパイラの最適化によって無効になるかわからない過酷な世界
気をつけるべき点
• RubyのAPIにはいくつかchar *を引数にとるものがありますが…(rb_str_newやrb_reg_newなど)
• ふつうにあります
• ただ、これに関してはRubyのAPI側で何とかすべきじゃないかと思わなくもない。 malloced memoryに対して一部保護を入れるなど
GC!Object Aの中身
Object Aの回収
Ruby Core
Object Aの中身を使おうとする
死亡!
まとめ• 拡張ライブラリは簡単にかけるよ
• たまには気をつけておかないと、GCで痛い目をみるよ
• でも、たまにだけだよ
• RubyのGCは完全に保守的なわけではなくて、Ruby Objectが入ってるHeapsしかみないよ
• RB_GC_GUARDは今の所、コンパイラの最適化とのおにごっこ
• 拡張ライブラリを書いたら一度はGC.stress=1で走らせておこう
• mallocで確保しているだけの領域にもなんらかの手当てがほしいなー
• (最近もRuby本体で今回の例と同じバグがありました…)
Rubyの書きやすさ+C言語のスピードの世界へようこそ!
hashベンチマーク(ソースは後)
mark user system total real
193p374 22.004 30.46 0.54 31 31.08143
200p195 17.09916 25.79 0.3 26.09 26.1964
r41094 14.4588 28.12 1.34 29.46 29.62575
r41095 12.13761 25.9 1.29 27.19 27.27527
r41097 7.250059 18.98 1.05 20.03 20.10459
r41128 6.633022 18.35 1.12 19.47 19.59778
r41325 1.272689 10.79 0.64 11.43 11.52074
r41634 0.870261 9.07 0.37 9.44 9.456588
0
5
10
15
20
25
30
35
193p374 200p195 r41094 r41095 r41097 r41128 r41325 r41634
mark
user
system
total
real一部
回数 r41634 Python 2.7.4
1000000 2.809293 1.559357
2000000 5.932282 3.421049
3000000 8.812863 5.801263
Pythonと適当に比較してみた(ソースは後)
Oprofile 取ってみたところ、支配的なのはst_lookupとsiphashが半々ぐらい