Firefox Hacks 翻訳日記

アクセスカウンタ

zoom RSS コンパートメント

<<   作成日時 : 2010/10/17 22:42   >>

トラックバック 0 / コメント 3

以下の記事は、Firefox 4 に搭載される(予定の) "Compartments"(または "GC Compartments") に関する記事、Compartments « Andreas Gal の全訳です。
旬の文書ですが技術系の文書なので、翻訳がこなれていない部分があるかと思います。
誤訳や訳文の改善についての指摘を歓迎します。



<2010年10月21日追記>
まず dynamis さんの講演スライド GC Compartments を見てからお読みいただくと、理解が深まるかもしれません。
<追記終わり>




ヒープ (Heap)


私たちは、Firefox が JavaScript オブジェクトを管理する方法に大きな変更を加えました。JavaScript オブジェクトと言えば、配列や日付のオブジェクトなどスクリプトによってインスタンス化されたものですが、入力欄や DIV 要素などの DOM (Document Object Model) 要素を JavaScript で表現した物も含まれます。Firefox はこれまで、全ての JavaScript オブジェクトを一つの JavaScript ヒープに格納していました。このヒープは、時々ガベージコレクションされます。つまり、ブラウザはヒープ中の全てのオブジェクト・グラフを見て回り、オブジェクトが参照可能かどうかを判断するのです。参照できないオブジェクトは配置から除外され、メモリ空間が回復します。

画像

ブラウザの全ての JavaScript オブジェクトを単一のヒープに格納する事が最善の策とは言えない理由はたくさんあります。もし、ユーザーが多数のウィンドウ(またはタブ)を開いていて、そのうちのどれかが多数のオブジェクトを生成したとすると、これらのオブジェクトの多くは参照不能(ゴミ)になっている可能性が高くなります。ブラウザがこの状態を発見すると、ガベージコレクションが動作します。不幸にして、ヒープには他のウィンドウ(またはタブ)からのオブジェクトも混在しているので、ブラウザはヒープ全体をチェックしなければなりません。アイドル状態になっているウィンドウが多数ある時、全体を見るのは非常に無駄な動作です。なぜなら、これらのウィンドウはゴミを生成していないからです。活動が活発な一つのウィンドウがガベージコレクションを発動した場合は、ガベージコレクションにかかる時間の多くが、グローバルなオブジェクト・グラフの無関係な部分を探査するのに費やされるのです。

Firefox では、この問題は他のブラウザよりも顕著に現れます。なぜなら、Firefox のユーザーインタフェースコード(chrome code とも呼ばれます。Google Chrome と混同しないでください)は JavaScript で実装されており、常に多数の chrome(ユーザーインタフェース)オブジェクトが存在しているからです。これらの UI オブジェクトは常駐する傾向があるので、ウェブコンテント・ウィンドウがガベージコレクションを動作させた場合、Firefox は chrome オブジェクトがまだ生きているかの判定に時間を取られ、アクティブなウェブコンテント・ウィンドウに集中する事ができません。


画像

コンパートメント (Compartments)


私たちは Firefox 4 で、JavaScript オブジェクトの管理方法を変更しました。私たちの JavaScript エンジンである SpiderMonkey (時には TraceMonkey あるいは JägerMonkey と呼ばれます。SpiderMonkey のトレースコンパイラと JIT コンパイラです) は、複数の JavaScript ヒープをサポートするようになりました。これを私たちはコンパートメント (compartments) と呼んでいます。同一の生成源(たとえば、“http://mail.google.com/” や “http://www.bank.com/”)による全てのオブジェクトは、個別のコンパートメントに格納されます。これによって、いくつかの重要な影響がもたらされます。

  • ウェブサイトによって作られた全てのオブジェクトが同じコンパートメントにあり、従って同じメモリ領域にある。これによって、キャッシュラインの偽共有(false sharing)が減少し、キャッシュの利用を改善できます。偽共有(false sharing)は、オブジェクトを操作したいが、キャッシュラインのデータ全体を CPU のキャッシュに読み込まなければならない時に発生します。今までの方式では、JavaScript オブジェクトは他の生成源からの任意のオブジェクトと混在していました。このようなクロスオリジンのオブジェクトが同時に使用される事は多くないので、キャッシュのヒット率を低下させていました。新しい方式では、一つのウェブサイトからのオブジェクトは、クロスオリジンのオブジェクトの混在なしに、メモリ上でまとめられます。

  • JavaScript オブジェクト(オブジェクトである JavaScript の function も含む)は、同じコンパートメントのオブジェクトしかアクセスできない。セキュリティの面からすると、この不変条件は非常に有用です。JavaScript エンジンは、この条件を非常に低いレベルで適用します。これによって、“google.com” のオブジェクトが、例えば “evil.com” のような信頼されないウェブサイトに間違ってリークされる、という事態は発生し得ないことになります。コンパートメントの壁を乗り越えられるのは、特別な種類のオブジェクトに限られます。このようなオブジェクトは、クロス・コンパートメント・ラッパー(cross compartment wrappers)と呼ばれます。クロス・コンパートメント・ラッパーの生成は追跡の対象になり、 外部からのリファレンスによってコンパートメント中のどのオブジェクトが生存し続けているかを、JavaScirpt エンジンはいつでも判断できるのです。従って、全体のガベージコレクションを行なうだけではなく、コンパートメント別のガベージコレクションを行なう事もできます。まず、コンパートメントの外部から参照されている全てのオブジェクトは生きていると前提し、次にコンパートメント内のオブジェクト・グラフを探査すれば良いわけです。参照元のないオブジェクトは破棄されます。この新しいコンパートメントごとのガベージコレクションによって、きっかけとなったウィンドウ(またはタブ)とは無関係のヒープ領域を探査する必要がなくなるのです。


ラッパー (Wrappers)


ラッパーは、Firefox においてもブラウザ全般においても、新しい概念ではありません。これまで私たちは、ウィンドウ(あるいはタブ)が相互にオブジェクトをやり取りする方式としてラッパーを使用してきました。今までは、あるウィンドウ(あるいはタブ)が別のウィンドウに所属するオブジェクトにさわろうとした場合、オブジェクトの代わりにラッパーが手渡されます。このラッパーオブジェクトは、アクセス元のウィンドウ(subject とも呼ばれます)が目的となるオブジェクトに対するアクセス権限を持っているかどうかを、アクセス時に動的にチェックします。例えば、Google Mail のウィンドウが別の Google Mail のウィンドウにアクセスしようとした場合、アクセスは許可されます。なぜなら、この二つのウィンドウ(またはタブないし iframe)は同一生成源であり、このアクセスを許可しても安全だからです。一方、信頼されないウェブサイトが Google Mail の DOM 要素へのリファレンスを持っている場合、同じラッパーが手渡され、そのサイトが Google Mail の DOM 要素にアクセスしようとした時点で、ラッパーはアクセスを拒否するでしょう。信頼されないウェブサイトである “evil.com” は “google.com”.とクロスオリジンだからです。

画像


Firefox 3.6 のラッパー方式(他のブラウザがラッパーを使用する方法もほぼ同様です)の欠点は、これらのラッパーが C++ によるブラウザの実装内で正しい位置に配置されなければならない、という点と、それぞれのラッパーがアクセス時に動的なセキュリティチェックをしなければならない、という点です。コンポーネントを使用すれば、はるかに良い運用ができます:

  • 同一生成源に属する全てのオブジェクトは同じコンパートメントにあり、かつ生成源が異なるオブジェクトはそのコンパートメントには存在しないので、コンパートメント内の全てのオブジェクトは、ラッパーを介する事なく、同じコンパートメント内の他のオブジェクトにアクセスできます。これは単にウィンドウ間の話だけではなく、iframe にも適用される、という点に注目してください。Google Mail のセッションは、相互に激しくオブジェクトのやり取りをする多数の iframe を使用する事がほとんどです。これまでは iframe 間のやりとりに、動的なセキュリティチェックを常に行なうラッパーを介さざるを得ませんでした。今後はその必要がなくなり、Google Mail のような iframe を多用するウェブアプリケーションにおいて、体感できるレベルの高速化が得られます。

  • 全てのクロスオリジンなオブジェクトは別のコンパートメントにあるので、セキュリティチェックを必要とするクロスオリジンなアクセスを発生させるのは、クロスコンパートメントラッパーだけです。このクロスコンパートメントラッパーはソースのコンパートメントに存在し、単一の目的オブジェクトにアクセスします。クロスコンパートメントラッパーが生成される時、ラッパーファクトリー (wrapper factory) によって、どのようなセキュリティポリシーが適用されるべきかが決定されます。例えば、“evil.com” が “google.com” のオブジェクトを参照している場合、そのオブジェクトに対するラッパーが、“evil.com”のコンパートメントに作成されます。このラッパーが生成される時に、ラッパーファクトリーは厳しいクロスオリジンのセキュリティポリシーを適用するので、“evil.com” が “google.com” のウィンドウから情報を探り出すのは不可能になります。これまでの方式のラッパーとは違い、このセキュリティポリシーは静的なのです。このラッパーを見れるのは “evil.com”のオブジェクトだけであり、目的のコンパートメントにある一つの DOM 要素しか参照していないので、アクセス時にポリシーを再チェックする必要はないのです。その代わり、“evil.com” が DOM 要素から情報を読み出そうとするたびに、生成源を比較するまでもなくアクセスは拒否されます。

画像


脳移植 (Brain Transplants)


JavaScript における DOM の表現で、特に興味深い奇異な点として、それぞれの DOM ウィンドウ(またはタブまたは iframe)に対して二つのオブジェクトが存在する、という点があります。インナーウィンドウ (inner window) とアウターウィンドウ (outer window) です。数年前にこの分割がウェブブラウザーに実装されたのは、新しい URL にナビゲートされるウィンドウを安全に取り扱うためでした。このようなナビゲーションが行なわれた時に、アウターウィンドウの中にあるインナーウィンドウのオブジェクトは新しいオブジェクトによって置換されます。一方、ウィンドウ(すなわちアウターウィンドウ)に対する実際のリファレンスは変更されません。もしこのナビゲーションによってウィンドウが新しい生成源になった場合、インナーウィンドウは適切な新しいコンパートメントに割り当てられなければなりません。もちろん、これによって新たな問題が発生します。アウターウィンドウは、もはや別のコンパートメントにあるので、直接新しいインナーウィンドウを指し示す事ができないのです。

この問題に対する私たちの解決法が、脳移植 (brain transplants) です。アウターウィンドウがナビゲートされるたびに、アウターウィンドウは新しいコンパートメントにコピーされます。古いコンパートメントのオブジェクトは、目的のコンパートメントで新たに作られたオブジェクトをポイントするクロスコンパートメントラッパーに変換されます。脳移植という用語が適切だとわかるでしょう。インナーウィンドウのオブジェクトが割り当てられるのと同じコンパートメントにある、新しいオブジェクトの外殻の中に、アウターウィンドウの内臓が移植されるのです。

プロセス分離 (Processes)


Google Chrome や Internet Explorer に使われているタブごとのプロセスと、コンパートメントとの違いが気になる読者もいるでしょう。多くの点でコンパートメントは似ていますが、違っている点も多々あります。どちらも JavaScript のオブジェクト間のアクセスを遮断する、という点では共通しています。最も重要な違いは、プロセス分離がハードウェア依存の強力な分離を行なうのに対して、コンパートメントは純粋にソフトウェア上での保障を行なう、という点です。しかし、コンパートメントの利点として、クロスコンパートメントのコミュニケーションがより効率的にできる、という事があげられます。コンパートメントでは、生成源の違うウェブサイト同士のやり取りは、(クロスオリジンのアクセスポリシーがきちんと行なわれていれば)少しの負荷で容易に達成できます。しかし、プロセス分離におけるプロセス間での JavaScript オブジェクトのアクセスは、不可能ないし非常に手間のかかるものになります。モダンブラウザでは、将来的に二つの形式の分離が併用される事になるでしょう。互いに交流する必要のない二つのウェブサイトは、別々のプロセスで生きていけます。一方、相互にアクセスが必要なクロスオリジンのウェブサイトは、セキュリティとパフォーマンスを向上させるためにコンパートメントを使用する事ができるのです。

未来 (Future)


私たちは、コンパートメントのメインのパッチを投入済みで、現在のナイトリービルド(そして Firefox 4 のベータ7)では、生成源ごとのコンパートメントによる JavaScript ヒープが実装されています。上記した機能のいくつか、特にコンパートメントごとのガベージコレクションは、ベータ8になるまで実現しないでしょう。現時点では、全てのコンパートメントが一斉にガベージコレクションされます。コンパートメントの導入によって築かれた基礎から、将来的な機能の拡張がいくつも可能になるでしょう。異なるタブに属するオブジェクトを明確に区別できるようになったので、JavaScript エンジンに対する将来の変更によって、個別のコンパートメントに対する JavaScript ガベージコレクションができるだけではなく、アクティブではない(つまり、その時点でイベントハンドラがトリガーされていない)コンテンツのガベージコレクションをバックグラウンドでできるようになるでしょう。



コメント欄から最初のコメントだけ抄訳しておきます。

コメント1:
これによってメモリの使用量は増加しますか?増加するとしたらどれくらい?

返信:
ブラウザセッション全体における影響は無視できる程度でしょう。
コンパートメントごとのヒープの作成には4Kのメモリを必要とします。
しかし、ラッパーの作成頻度が低下するので、そのぶんメモリの使用量は下がります。
従って、行って来いでチャラになるでしょう。



<2010年10月19日追記>
コメント欄の dynamis さんのアドバイスに従って、訳文を一部修正しました。
dynamis さん、ありがとうございます。
<追記終わり>

テーマ

関連テーマ 一覧


月別リンク

トラックバック(0件)

タイトル (本文) ブログ名/日時

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(3件)

内 容 ニックネーム/日時
素早くかつスバラシイ翻訳に感謝です!m(_ _)m
意味的に気になったところが少しあるので書いておきます:

CPU のキャッシュから全てのデータのキャッシュラインを読み込まなければならない時に発生します。
-> キャッシュラインのデータ全体を CPU のキャッシュに読み込まなければならない時に発生します。
# データを CPU のキャッシュに読み込むのが(オブジェクトより大きな)ライン単位である場合、同一ラインに無関係なデータがあるとキャッシュヒット率が下がるという話。データを全部読むわけではない。

JavaScript エンジンは、外部のリファレンスによってコンパートメントからのオブジェクトが生かされ続けているか、を常に知っています。
-> (クロスコンパートメントラッパーを介した)外部からのリファレンスによって、コンパートメント中のどのオブジェクトが生存し続けるか、JavaScirpt エンジンはいつでも判断できるのです。

インナーウィンドウは適切な新しいコンパートメントに移動されなければなりません
-> ...割り当てられなければなりません
インナーウィンドウのオブジェクトが移動されたのと同じ
-> インナーウィンドウのオブジェクトが割り当てられるのと同じ
# メモリの allocate は普通は割り当てだし、インナーウィンドウのオブジェクトは移動やコピーはしないと思うので

JavaScript のオブジェクトを保護します
-> JavaScript のオブジェクト間のアクセスを遮断します
# each other という語句に(別プロセス、別コンパートメント間のという意味がこもってるので)
dynamis
2010/10/19 15:53
ちなみに inner/outer window の話はこの辺が参考になりました:

https://developer.mozilla.org/en/Inner_and_outer_windows
https://developer.mozilla.org/En/SpiderMonkey/Split_object
https://bugzilla.mozilla.org/show_bug.cgi?id=296639
dynamis
2010/10/19 15:55
dynamis さん、アドバイスありがとうございます。
久しぶりのまともな翻訳でしたが、大きくは外していなかったようで、一安心です。
ご指摘はほぼそのままいただきました。
また何かありましたら、よろしくお願いします。
池田
2010/10/19 21:27

コメントする help

ニックネーム
本 文
コンパートメント Firefox Hacks 翻訳日記/BIGLOBEウェブリブログ
文字サイズ:       閉じる