[52] [[HTML]] や [[DOM]] は様々な[[オブジェクト]]やそれに類するもので構成されています。 それらは[[文書]] ([[Webアプリケーション]]) を構成する要素として存在していたり、 [[スクリプト]]によって操作されたりします。どこからも[[参照]]されなくなり、 [[スクリプト]]上も[[利用者界面]]上も意義を失った[[オブジェクト]]等は[DFN[[RUBYB[ごみ収集]@en[garbage collection]]]]され、 破棄されます。それはすなわち [[Webブラウザー]]実行環境の[[メモリー]]から削除され、 動作もアクセスもできなくなることを意味します。 * 仕様書 [REFS[ - [2] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [6] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [9] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [11] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [20] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [24] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [22] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [25] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [31] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [38] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [44] [CITE@en-US[DOM Standard]] ([TIME[2012-11-16 19:17:11 +09:00]] 版) - [46] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [49] [CITE@en-US-x-hixie[HTML Standard]] ([TIME[2012-11-16 20:26:18 +09:00]] 版) - [53] [CITE@en-US[XMLHttpRequest Standard]] ([TIME[2012-11-14 13:48:01 +09:00]] 版) ]REFS] * ごみ収集と参照 [51] [[HTML]] も [[DOM]] も、「[DFN[[RUBY[ごみ収集][ガーベージ・コレクション]@en[garbage collection]]]]」、 「[DFN[[RUBYB[強参照]@en[strong reference]]]]」、「[DFN[[RUBYB[弱参照]@en[weak reference]]]]」 といった用語を定義なしで使っており、[[計算機科学]]分野での一般的な単語として用いていると思われます。 [WEAK[(なお [[HTML]] は「[[弱参照]]」という用語を使っていません。)]] * 暗示強参照 [3] 既存の[[オブジェクト]]を返す[[IDL属性]]からは、その[[オブジェクト]]への[DFN[[RUBYB[[[暗示強参照]]]@en[implied strong reference]]]]があります。 [SRC[>>2]] [EG[ [4] 例えば [CODE(JS)@en[[[document]].[[location]]]] [[属性]]は [CODE(DOMi)@en[[[Location]]]] [[オブジェクト]]を持っているので、これはすなわち、当該 [CODE(DOMi)@en[[[Document]]]] [[オブジェクト]] [WEAK[(の [CODE(DOMa)@en[[[location]]]] [[属性]])]] から [CODE(DOMi)@en[[[Location]]]] [[オブジェクト]]への[[強参照]]があることになります。 ]EG] [EG[ [5] [CODE(DOMi)@en[[[Document]]]] からその[[子孫節点]]へは [WEAK[([CODE(DOMa)@en[[[childNodes]]]] [[属性]]などを通じて)]] [[強参照]]があり、また各[[節点]]から [CODE(DOMi)@en[[[Document]]]] へは [WEAK[([CODE(DOMa)@en[[[ownerDocument]]]] [[属性]]などを通じて)]] [[強参照]]があります。 ]EG] * 閲覧文脈 [13] [[利用者エージェント]]は[[最上位閲覧文脈]]に対して[[強参照]]を持っています。 [SRC[>>11]] ;; [18] [[利用者エージェント]]から[[閲覧文脈]]への[[強参照]]は[[閲覧文脈を捨てる]][[算法]]で削除されます。 [12] [[閲覧文脈]]は、その [CODE(DOMi)@en[[[Document]]]] 群とその [CODE(DOMi)@en[[[WindowProxy]]]] に対して[[強参照]]を持っています。 [SRC[>>11]] ;; [17] [[閲覧文脈]]から [CODE(DOMi)@en[[[Document]]]] への[[参照]]は[[[CODE(DOMi)@en[Document]]を捨てる]][[算法]]で削除されます。 [14] [CODE(DOMi)@en[[[Document]]]] はその [CODE(DOMi)@en[[[Window]]]] に対して[[強参照]]を持っています。逆に [CODE(DOMi)@en[[[Window]]]] は [CODE(DOMa)@en[[[document]]]] [[属性]]を通じて[[暗示強参照]]を持っています。 [SRC[>>11]] [15] [CODE(DOMi)@en[[[Window]]]] は [CODE(DOMi)@en[[[window]]]] など、 [CODE(DOMi)@en[[[Document]]]] は [CODE(DOMi)@en[[[defaultView]]]] などを通じて [CODE(DOMi)@en[[[WindowProxy]]]] への[[暗示強参照]]を持っています。 [SRC[>>11]] [16] [[スクリプト]]はその[[閲覧文脈]]と[[文書]]に対して[[強参照]]を持っています。 [SRC[>>11]] [19] [[最上位閲覧文脈]]でない[[閲覧文脈]]の [CODE(DOMi)@en[[[WindowProxy]]]] が[[ごみ収集]]の対象になると、 当該[[閲覧文脈]]は[[閲覧文脈を捨てる]][[算法]]により処理されなければなりません。 [SRC[>>11]] * 変異観察器 [45] [[節点]]は、[[登録済み観察器]]のリストにある[[登録済み観察器]]に対する[[強参照]]を持ちます。 逆方向には[[弱参照]]を持ちます。 [SRC[>>44]] * ワーカー [21] [CODE(DOMi)@en[[[DedicatedWorkerGlobalScope]]]]/[CODE(DOMi)@en[[[Worker]]]] は暗示的に関連付けられた [CODE(DOMi)@en[[[MessagePort]]]] [[オブジェクト]]を有しますが、この [CODE(DOMi)@en[[[MessagePort]]]] は [CODE(DOMi)@en[[[DedicatedWorkerGlobalScope]]]]/[CODE(DOMi)@en[[[Worker]]]] より先に[[ごみ収集]]しては[['''なりません''']]。 [SRC[>>20, >>24]] [23] [[ワーカー]]の[[実行時誤り]]は [CODE(DOMe)@en[[[error]]]] [[事象]]として呼び出し元の [CODE(DOMi)@en[[[Worker]]]] や [CODE(DOMi)@en[[[Document]]]] へと伝達されていきますが、その伝達先が既に[[ごみ収集]]されて消失している場合には [CODE(DOMa)@en[[[onerror]]]] は [CODE@en[[[null]]]] であるものとして [WEAK[(つまり何もしないで更に上位の呼び出し元へと伝達されるよう)]] 処理されます。 [SRC[>>22]] * [CODE(DOMi)@en[MessagePort]] [41] [CODE(DOMi)@en[[[MessagePort]]]] が [[entangle]] されると、 その [CODE(DOMi)@en[[[MessagePort]]]] と [[entangle]] された [CODE(DOMi)@en[[[MessagePort]]]] が最初の [CODE(DOMi)@en[[[MessagePort]]]] への[[強参照]]を持つか、 または最初の [CODE(DOMi)@en[[[MessagePort]]]] の[[所有者]]が 最初の [CODE(DOMi)@en[[[MessagePort]]]] への[[強参照]]を持つかのいずれかであるかのように扱われなければ[['''なりません''']]。 従って [CODE(DOMi)@en[[[MessagePort]]]] を受け取って[[事象聴取器]]を登録してからその [CODE(DOMi)@en[[[MessagePort]]]] への明示的な参照を捨てたとしても、 その[[事象聴取器]]が[[メッセージ]]を受信できる限りにおいて[[通信路]]は維持されることになります。 もちろん[[通信路]]の両端で同様に参照が破棄された場合にはいずれの側も[[アプリケーション]]から到達できなくなりますから、 両 [CODE(DOMi)@en[[[MessagePort]]]] を[[ごみ収集]]することができます。 [SRC[>>38]] [42] [CODE(DOMi)@en[[[MessagePort]]]] は、当該[[オブジェクト]]で [[dispatch]] されることになる[[メッセージ]]が[[タスク源]]に存在する間、 あるいは[[ポート・メッセージ・キュー]]が開いていて [CODE(DOMe)@en[[[message]]]] [[事象]]が存在している場合には、[[ごみ収集]]しては[['''なりません''']]。 [SRC[>>38]] [39] [CODE(DOMi)@en[[[PortCollection]]]] は [CODE(DOMi)@en[[[MessagePort]]]] を零個以上保有することができる[[オブジェクト]]ですが、[[強参照]]ではないので [CODE(DOMi)@en[[[MessagePort]]]] の[[ごみ収集]]を防ぐ役割は持たず、 [[ごみ収集]]された [CODE(DOMi)@en[[[MessagePort]]]] は削除されていきます。 [SRC[>>38]] [43] [CODE(DOMi)@en[[[MessagePort]]]] が不要になったら、明示的に閉じて [[disentangle]] することが[RUBYB[強く勧められています]@en[strongly encouraged]]。 明示的に閉じずないと必ずしも即座に[[ごみ収集]]されるとは限らないため、 [[メモリー]]を無駄にすることとなります。 [SRC[>>38]] ** 歴史 [REFS[ - [66] [CITE@en[Web Applications 1.0 r2357 Define MessagePort such that they won't be garbage collected while a message is outstanding. (credit: ap)]] ([TIME[2008-10-21 04:18:00 +09:00]] 版) - [65] [CITE@en[Web Applications 1.0 r2024 Simplify garbage collection for ports even further. Define dicarding of Document objects better for ports. Prevent inactive documents from receiving messages.]] ([TIME[2008-08-06 16:57:00 +09:00]] 版) ]REFS] * 画像 [47] [RUBYB[[[画像データの更新]]]@en[update the image data]][[算法]]の実行中は、 その対象となっている [CODE(HTMLe)@en[[[img]]]] [[要素]]の[[文書]]から当該[[要素]]への[[強参照]]があるとしなければ[['''なりません''']]。 [SRC[>>46]] ;; [48] [[[CODE(DOMi)@en[Document]]中]]にある[[要素]]なら自然に満たされますが、 そうではなく単独で存在する [CODE(HTMLe)@en[[[img]]]] [[要素]]であっても、 [[画像]]の読み込みが終わるまでは破棄されないことになります。 [50] [CODE(DOMi)@en[[[CanvasProxy]]]] は[[無効]]でなければ対応する[[画布要素]]への[[強参照]]があるとしなければ[['''なりません''']]。 [SRC[>>49]] * 媒体要素 [7] [[媒体要素]]は、それに対するすべての[[参照]]が削除されただけの理由で[RUBYB[[[再生]]]@en[playing]]を停止しては[['''なりません''']]。 それ以上[RUBYB[[[音声]]]@en[audio]]を再生できない状態になった時、当該[[媒体要素]]は[[ごみ収集]]して[['''構いません''']]。 [SRC[>>6]] [8] [[要素]]に対して明示的に[[参照]]が存在しておらず、まだ[RUBYB[活性的に再生]@en[actively playing]]されていなくとも、 [[音声]]の[[再生]]のために存在し続けることがあります。例えばまだ[[参照]]されている[[現在媒体制御器]]があって[RUBYB[再生再開]@en[unpause]]できるかもしれませんし、 あるいは再生再開されていても[[バッファ]]待ちのため [[stall]] 中かもしれません。 [SRC[>>6]] ;; [10] 環境によっては同時再生数の制限が厳しいかもしれませんから、 再生が終わったらすべての[[参照]]を確実に削除するなど配慮することが特に好ましいとされています。 [SRC[>>9]] * WebRTC @@ [64] [CITE@en[WebRTC 1.0: Real-time Communication Between Browsers]] ([TIME[2012-11-15 19:30:32 +09:00]] 版) @@ [63] [CITE@en-us[Media Capture and Streams]] ([TIME[2012-11-15 19:30:32 +09:00]] 版) * XHR [54] [CODE(DOMi)@en[[[XMLHttpRequest]]]] [[オブジェクト]]は次の場合[[ごみ収集]]しては[['''なりません''']]。 [SRC[>>53]] - [55] 次のいずれかが成立し、 -- [56] 状態が [CODE(DOM)@en[[[OPENED]]]] であり [[[CODE(DOMm)@en[send()]]フラグ]]が設定されている -- [57] 状態が [CODE(DOM)@en[[[HEADERS_RECEIVED]]]] -- [58] 状態が [CODE(DOM)@en[[[LOADING]]]] - [59] かつ次のいずれかが成立する場合 -- [60] [CODE(DOMe)@en[[[readystatechange]]]], [CODE(DOMe)@en[[[progress]]]], [CODE(DOMe)@en[[[abort]]]], [CODE(DOMe)@en[[[error]]]], [CODE(DOMe)@en[[[load]]]], [CODE(DOMe)@en[[[timeout]]]], [CODE(DOMe)@en[[[loadend]]]] のいずれかの[[事象聴取器]]が登録されている場合 -- [61] [[アップロード完了フラグ]]が設定されておらず関連付けられた [CODE(DOMi)@en[[[XMLHttpRequestUpload]]]] [[オブジェクト]]が [CODE(DOMe)@en[[[progress]]]], [CODE(DOMe)@en[[[abort]]]], [CODE(DOMe)@en[[[error]]]], [CODE(DOMe)@en[[[load]]]], [CODE(DOMe)@en[[[timeout]]]], [CODE(DOMe)@en[[[loadend]]]] のいずれかの[[事象聴取器]]が登録されている場合 [62] [CODE(DOMi)@en[[[XMLHttpRequest]]]] [[オブジェクト]]の[[接続]]が開いたまま[[ごみ収集]]される場合、 [[fetch]] をすべて取り消し、それらにより追加された[[タスク]]をすべて破棄し、 またそれらによりネットワークから受信しているデータがあれば破棄しなければ[['''なりません''']]。 [SRC[>>61]] * 事象源 [26] [CODE(DOMi)@en[[[EventSource]]]] については、 - [28] [CODE(DOMa)@en[[[readyState]]]] が [CODE[[[CONNECTING]]]] であり、かつ [CODE(DOMe)@en[[[open]]]], [CODE(DOMa)@en[[[message]]]], [CODE(DOMa)@en[[[error]]]] のいずれかの[[事象聴取器]]が登録されている場合 - [27] [CODE(DOMi)@en[[[EventSource]]]] の [CODE(DOMa)@en[[[readyState]]]] が [CODE[[[OPEN]]]] であり、かつ [CODE(DOMa)@en[[[message]]]], [CODE(DOMa)@en[[[error]]]] のいずれかの[[事象聴取器]]が登録されている場合 - [29] [[遠隔事象タスク源]]に[[タスク]]が投入されている間 ... には、 [CODE(DOMi)@en[[[EventSource]]]] の[[構築子]]が呼び出された [CODE(DOMi)@en[[[Window]]]] または [CODE(DOMi)@en[[[WorkerUtils]]]] から [CODE(DOMi)@en[[[EventSource]]]] への[[強参照]]がなければ[['''なりません''']]。 [SRC[>>26]] [30] [CODE(DOMi)@en[[[EventSource]]]] の[[接続]]が開いている間に同オブジェクトが[[ごみ収集]]される場合、当該オブジェクトによって開かれた [[fetch]] は中断しなければ[['''なりません''']]。 [SRC[>>26]] * Web Sockets [32] [CODE(DOMi)@en[[[WebSocket]]]] [[オブジェクト]]は[[イベント・ループ]]によって直近の[[タスク]]が実行開始された時点の [CODE(DOMa)@en[[[readyState]]]] について、 - [33] [CODE(DOMc)@en[[[CONNECTING]]]] であれば、 [CODE(DOMm)@en[[[open]]]], [CODE(DOMm)@en[[[message]]]], [CODE(DOMe)@en[[[error]]]], [CODE(DOMm)@en[[[close]]]] - [34] [CODE(DOMc)@en[[[OPEN]]]] であれば、 [CODE(DOMm)@en[[[message]]]], [CODE(DOMe)@en[[[error]]]], [CODE(DOMm)@en[[[close]]]] - [35] [CODE(DOMc)@en[[[CLOSING]]]] であれば、 [CODE(DOMe)@en[[[error]]]], [CODE(DOMm)@en[[[close]]]] のいずれかの[[事象聴取器]]が登録されている場合には、[[ごみ収集]]しては[['''なりません''']]。 [SRC[>>31]] [36] また、 [CODE(DOMi)@en[[[WebSocket]]]] [[オブジェクト]]は、 [[確立された接続]]があってネットワーク転送するデータがキューにある場合には[[ごみ収集]]しては[['''なりません''']]。 [SRC[>>31]] [37] [CODE(DOMi)@en[[[WebSocket]]]] [[オブジェクト]]が[[接続]]が開いたまま[[ごみ収集]]される場合は、 [RUBYB[[[閉じ]]][Close]]メッセージの[[状態符号]]なしで[RUBYB[[[WebSocket閉じハンドシェイクを開始]]]@en[start the WebSocket closing handshake]]しなければ[['''なりません''']]。 [SRC[>>31]] * 歴史 [1] [[Web]] における[[ごみ収集]] ([[garbage collection]]) は [[HTML Living Standard]] ではじめて明示的に規定され、 その後他の仕様でも定義されるようになりました。