JAVA(Android)のメモリ管理

@akisutesama さんのJAVAのメモリ管理を理解する行程が非常にいいと感じたので、残しておきます。
20
akisute/Masashi Ono @akisutesama

まずiOS(Cocoa Touch, Objective-C)とWindows(Silverlight/WinRT, C#)の場合を考える。iOSの場合はdelegate, KVO, NSNotificationCenterがある。

2011-09-18 16:09:41
akisute/Masashi Ono @akisutesama

Windowsの場合はC#であればdelegateとそれをさらに拡張したeventの仕組みで一発解決する。これが一対一と一対多を兼ねる。参照先をweak referenceするから循環参照の危険もない。

2011-09-18 16:10:53
akisute/Masashi Ono @akisutesama

多対多はどうすればいいのか正直わからないのだが、そういう仕組みがあるらしいということは聞いている。最も、たいていの場合は一対多で事足りるけど。

2011-09-18 16:12:23
akisute/Masashi Ono @akisutesama

最後に問題のJavaだ。Androidを想定する。一対一の場合はInterfaceとそれを継承したクラスのインスタンスを渡すことで通知を行うのがほぼ通例だ。一対多は全くわからない。多対多もさっぱりだ。

2011-09-18 16:13:12
akisute/Masashi Ono @akisutesama

一対多と多対多は後ほど考えるとして、まず一対一。さっきのInterfaceとそれを継承したインスタンス渡しというのはiOSのdelegateの実装と基本同じである。問題はそこにメモリの話が付いてくる。iOSにはweak referenceがある。しかしAndroidの場合は?

2011-09-18 16:15:10
akisute/Masashi Ono @akisutesama

当然Javaにもweak referenceはある。java.lang.ref.WeakReference<T>がそれだ。きちんとそれを使って構築されているのだろうか。

2011-09-18 16:16:35
akisute/Masashi Ono @akisutesama

さらに問題になるのが、そういうdelegateがweak referenceとして渡したインスタンスを保持しているのか、それとも保持していない(すぐに使って捨てる)のかが明示的になっているケースが見当たらない(俺調べ)という点だ。iOSの場合はweak referenceが自明。

2011-09-18 16:18:17
akisute/Masashi Ono @akisutesama

weak referenceなら自分がそのインスタンスを責任持って抱えないと(抱える仕組みを使わないと)GCされて死ぬ。そうでないなら自分が責任持ってそのインスタンスを使用後破棄しないとメモリリークして死ぬ(気がする。gcが循環参照を綺麗に捨ててくれるなら別)。

2011-09-18 16:19:08
kishikawa katsumi @k_katsumi

@akisutesama Androidは参照カウンタじゃないからそこが循環参照してても別にいいんじゃないの?ダメなのですか?

2011-09-18 16:20:04
akisute/Masashi Ono @akisutesama

というメモリ周りの話がまるで表に出てきて見えないのがJavaのすげぇ困ったところなのである。そこで質問。JVMは循環参照してても全然問題なくgcしてくれるから気にしないで通常の強参照(フィールド)に突っ込んじゃって全然OKなのか、否か。この程度のこともわからん程度すすんません><

2011-09-18 16:21:24
akisute/Masashi Ono @akisutesama

ここで、もし答えが「大丈夫だ、問題ない」であったとしても、だ。強参照同士で相互ループしているだけならいい。それら両方が死んだら死ぬのだから。しかしもし万が一何かの間違いでほぼ永続するインスタンスからそれらのどちらかが強参照されてしまったら?・・・死亡確定。ってこれはどこでも同じか

2011-09-18 16:22:33
akisute/Masashi Ono @akisutesama

書いてたらなんか大丈夫そうってことがわかってきた。JVMすげぇ。やべぇ。

2011-09-18 16:23:00
akisute/Masashi Ono @akisutesama

Effective Javaを読んでみよう。

2011-09-18 16:24:12
kishikawa katsumi @k_katsumi

@akisutesama いや、Androidで例外はあるのかもしれないけど、循環参照しててもルートから辿れないオブジェクトはGCのタイミングで破棄されるよ。JVMっていうかGCのアルゴリズムの話かな。

2011-09-18 16:28:03
akisute/Masashi Ono @akisutesama

@k_katsumi ですよねぇ。うん。大丈夫だ。参照カウントじゃないからすげー頭いい。

2011-09-18 16:28:39
akisute/Masashi Ono @akisutesama

あと、匿名クラスのインスタンスとか、内部クラスとかstatic内部クラスとかのメモリの絡みが一マイクロメートルもわからん。俺の情弱認識では、内部クラスは親クラスのインスタンスに対して強参照を持っている。匿名クラスは匿名クラスを生成したクラスが内部クラスを作ったのと同じ状態になる。

2011-09-18 16:28:56
hiratara @hiratara

@akisutesama Javaはリファレンスカウンタ方式じゃないので大丈夫ですよ。リファレンスカウンタだと循環参照だと解放しても0にならないって問題がおきますが、JavaのGCはルート集合から辿れない物は全て破棄なんで、循環してても関係ないです。

2011-09-18 16:30:40
akisute/Masashi Ono @akisutesama

ということでまとめ。Javaの場合は強参照とか気にする必要がありません。インスタンス渡せばおk。たとえ相互参照していてもgc様が綺麗に解決してくれますひゃっほう。やったねたえちゃん!

2011-09-18 16:32:20
akisute/Masashi Ono @akisutesama

とか考えながらjava.lang.refを見ていたらWeakの他にSoftとかPhantomとかあった。どういうことなの・・・

2011-09-18 16:32:46
akisute/Masashi Ono @akisutesama

Effective Javaはお作法の本であってメモリ関連のお話はしてくれないのでありました。ガハァ。

2011-09-18 16:35:32
akisute/Masashi Ono @akisutesama

こんなとき佐藤太一がいてくれれば・・・「JVMのソース嫁」とアドバイスをしてくれるものを・・・

2011-09-18 16:36:53
1 ・・ 4 次へ