ひがやすを技術ブログ

電通国際情報サービスのプログラマ

HOT reloadingとClassLoaderを理解しよう

JavaではClassはClassLoaderに読み込まれます。これはほとんどの人が知っていると思います。AOPを使うときのエンハンスされたクラスも同様にClassLoaderに読み込まれます。
これらの情報は、パーマネント領域に格納されますが、ClassLoaderがGCされると解放されます。


Seasar2のHOT reloadingでは、リクエストの度にClassLoaderを作って、そこにClassをロードし、そのClassLoaderは、リクエストが終わったら破棄しているので、Classの情報は、リクエストごとに破棄されています。
HOT relodingによって、パーマネント領域が使いつくされることはありません。


さらっと書きましたが、きちんとClassLoaderを破棄するのは、かなり大変です。リフレクションの情報がキャッシュされているとそれだけで破棄されなくなってしまうからです。
Seasar2のHOT reloadingの歴史は、ClassLoaderの破棄とClassCastExceptionとの戦いだったといっても過言ではないでしょう。
Seasar2のHOT reloadingは、開発が始まってから、もう3年以上がたち、かなり成熟しているので、ClassLoaderの破棄に関しては完全に問題はありません。
ClassCastExceptionに関しては、HOT reloadingされていないクラスから、HOT realodingされたくらすを直接触ると起きますが、結構bad know howがたまっているので、それでカバーといった感じですね。


HOT reloadingを実現するためにClassLoaderを毎回変えるというアプローチ(Seamもそう)は、仕組みは簡単ですが、きちんと動かすにはかなりのknow howが必要です。Seasar2なみにHOT reloadingを成熟させるには、かなり時間がかかるんじゃないかなぁと思います。


さっき、リフレクション情報がキャッシュされるとClassLoaderがうまく破棄されないと書きましたが、パフォーマンスのからみで、HOT reloadingではないとき(本番環境とか総合テスト環境とか)は、リフレクション情報をキャッシュしたいわけです。
この辺の作りをどうするのかも、かなりknow howが必要で、つかわれるすべてのフレームワークがこの辺のことを意識していなければいけません。だから、大変なのです。
Seasar2フルスタックで提供しているのは、この辺の絡みもあります。
SAStrutsでもHOT reloadingを実現していますが、Strutsそのものは、HOT reloadingをまったく考慮していません。この辺は、特定のクラスを拡張して対応しています。


そうそう、SpringやHibernateでテストする時にテストメソッドの度にフレームワークを初期化しているとパーマネント領域を食いつぶしてしまうのは、初期化の度にエンハンスされた新しいクラスがデフォルトのClassLoaderにロードされるためです。
Seasar2では、テストメソッドごとにClassLoaderを作っては破棄しているので、そのような問題は起きません。