マダカレークッテナイデショー

お仕事SE、趣味ドラム

イベントはちゃんと管理しないとメモリリークする

C#/WPFの話題。

 

メモリリーク

メモリリーク (Memory leak) とは、プログラミングにおけるバグの一種。 プログラムが確保したメモリの一部、または全部を解放するのを忘れ、確保したままになってしまうことを言う。 プログラマによる単純なミスやプログラムの論理的欠陥によって発生することが多い。

メモリリーク - Wikipedia

 

プログラマによる単純なミス」

 

、、、すいません

 

C#とかの言語を扱ってるとガーベッジコレクションが働いてくれるので、基本的には「何それおいしいの」状態だったのですが、そういうわけにはいかない。

 

以下、MVVMパターン前提で話します。

なぜ?

View→ViewModel にイベントを購読していると、内部的にはView←ViewModelに強い参照が発生している。なので、Viewがいらなくなったタイミングで破棄しても、内部的にはViewを参照し続けている輩が残ってるので、ガーベッジコレクションの対象とならず、メモリリークの原因となってしまう。

 

どんなとき起こりやすい?

イベントの購読者と発行者のライフサイクルが異なる(購読者のほうが短い)場合。

例えば、ボタンを押したらそのたびにダイアログを生成するけど、ViewModelはつかいまわすぜ、というような[Viewのライフサイクル] < [ViewModelのライフサイクル] の場合。ライフサイクルが一緒の場合は特に気にしなくてもいい。

 

どうすりゃいいの?
  • イベントはつけたらどっかで外す
  • WeakEventListenerを使う

など。

前者は、場合によっては開発者側でイベントの解除が明示的に書けない場合がある(らしい)。いちいち気にするのもめんどくさい。

そこで、後者。

強い参照でなく、弱い参照(WeakReference)の場合、参照が残っていてもガーベッジコレクションで回収してくれる。んなわけで、WeakEventListenerを使うと、特に購読者側で解放タイミングを気にしなくていい。(その代わり、若干特殊な実装が必要になる。)

 

一度仕組みを作ってしまえば、アーキテクチャレベルで対策ができるため、実装時に余計なことを気にすることがなくていい感じ。

 

実装時には、以下のようなページでおべんきょうさせていただきました。

(このページ見るよりはやいね。)

 

ugaya40.hateblo.jp

 

blog.okazuki.jp

 

 

以上