V8内郚メカニズムずオブゞェクトプロパティの迅速な䜜業

この資料では、V8の内郚メカニズムがJavaScriptオブゞェクトのプロパティずどのように機胜するかに焊点を圓おおいたす。 JavaScriptの芳点からプロパティを怜蚎する堎合、それらの異なるタむプは互いにそれほど異なりたせん。 JSオブゞェクトは通垞、文字列キヌず任意のオブゞェクトを倀ずしお持぀蟞曞のように動䜜したす。 ただし、蚀語仕様を読むず、たずえば、列挙されたずきに異なるタむプのプロパティの動䜜が異なるこずがわかりたす。 他の堎合では、さたざたな皮の特性の振る舞いは基本的に同じに芋えたす。

プロパティの類䌌性を考慮したプロパティの操䜜メカニズムの実装は、それほど倧芏暡なタスクではないように芋えたすが、V8腞では、プロパティを衚すいく぀かの異なる方法が䜿甚されたす。 これは、最初に高いパフォヌマンスを確保するために行われ、次にメモリを節玄するために行われたす。

画像

この蚘事では、オブゞェクトの動的に远加されたプロパティを凊理するずきにV8がどのように高いパフォヌマンスを実珟するかに぀いお説明したす。 V8でJavaScriptの実行を最適化する方法の本質、䟋えば組み蟌みキャッシュなどを理解するには、プロパティを操䜜するメカニズムの機胜の知識が必芁です。

ここでは、V8が名前付きプロパティず敎数でむンデックス付けされたプロパティを凊理する方法に぀いお説明したす。 その埌、新しい名前付きプロパティをオブゞェクトに远加するずきに、非衚瀺クラスの機胜の特城を考慮したす。これにより、オブゞェクトの圢状をすばやく識別できたす。 次に、V8の内郚メカニズムに぀いおの話を続け、非衚瀺のプロパティを䜿甚する機胜に応じお、目的の最適化を衚瀺したす。 最埌のセクションを確認した埌、敎数がむンデックス付けされたプロパティたたはむンデックスが割り圓おられた配列芁玠をV8がどのように凊理するかを孊習したす。

名前付きプロパティず配列芁玠の比范


非垞に単玔なオブゞェクトを分析するこずから始めたしょう。 たずえば、 {a: "foo", b: "bar"}たす。 このオブゞェクトには、 bずbずいう2぀の名前付きプロパティaありたす。 このオブゞェクトには、プロパティ名の敎数むンデックスがありたせん。 より䞀般的に芁玠ずしお知られるむンデックス付きプロパティは、配列の特性です。 たずえば、配列["foo", "bar"]は2぀のむンデックス付きプロパティがありたす0は倀fooで、 1は倀barです。 V8で名前付きプロパティずむンデックス付きプロパティを衚す実装の最初の䞻芁な違いに぀いお説明したした。

次の図は、通垞のJavaScriptオブゞェクトがメモリ内でどのように芋えるかを瀺しおいたす。


名前付きおよびむンデックス付きプロパティ

芁玠ずプロパティはさたざたなデヌタ構造に保存されたす。 これにより、新しいプロパティず芁玠を远加したり、それらを操䜜するためのさたざたなテンプレヌトでそれらにアクセスしたりする操䜜の効率が向䞊したす。

芁玠は、䞻にpopやsliceなどのさたざたなArray.prototypeメ゜ッドに䜿甚されslice 。 これらの関数が次々に続くプロパティで機胜するこずを考えるず、V8の内郚衚珟は、ほずんどの堎合、単玔な配列のように芋えたす。

埌で、メモリを節玄するためにむンデックス付きプロパティを保存するための蟞曞メカニズムの䜿甚に切り替える状況に぀いお説明したす。 特に、スパヌス配列を蟞曞に眮き換えるこずに぀いお話しおいたす。

名前付きプロパティは同様に別の配列に保存されたす。 ただし、芁玠ずは異なり、キヌを䜿甚しおプロパティストア内の䜍眮を芋぀けるこずはできたせん。 远加のメタデヌタが必芁です。 V8では、すべおのJavaScriptオブゞェクトに隠しクラスHiddenClassが関連付けられおいたす。 隠しクラスには、オブゞェクトの圢状に関する情報、特にプロパティ名ずプロパティストア内のむンデックスの察応に関する情報が栌玍されたす。 耇雑な䜜業シナリオでは、単玔な配列ではなく蟞曞を䜿甚しおプロパティを保存するこずがありたす。 察応するセクションでは、これに぀いおさらに詳しく説明したす。

▍結論



非衚瀺のクラスず蚘述子配列


芁玠ず名前付きプロパティの䞻な違いが䜕であるかを理解したら、V8で非衚瀺のクラスがどのように機胜するかを調べる必芁がありたす。

非衚瀺のクラスには、オブゞェクトのプロパティの数やプロトタむプぞのリンクなど、オブゞェクトに関するメタ情報が栌玍されたす。 隠しクラスは、兞型的なオブゞェクト指向プログラミング蚀語のクラスず抂念的に䌌おいたす。 ただし、JavaScriptなどのプロトタむプベヌスの蚀語では、通垞、オブゞェクトクラスに぀いお事前に知るこずはできたせん。 その結果、この堎合V8では、非衚瀺のクラスがオンザフラむで䜜成され、オブゞェクトが曎新されるず動的に曎新されたす。

非衚瀺のクラスは、オブゞェクトの圢状の識別子ずしお機胜するため、最適化V8コンパむラず組み蟌みキャッシュメカニズムの非垞に重芁な郚分です。 たずえば、最適化コンパむラは、隠しクラスずオブゞェクトの構造の互換性を保蚌できる堎合、適切なデヌタ構造にプロパティ倀を埋め蟌むこずを利甚できたす。

隠されたクラスの重芁な郚分を芋おください。


JSオブゞェクト、非衚瀺クラス、および名前付きプロパティに関する情報を含む蚘述子

V8では、JSオブゞェクトの最初のフィヌルドは非衚瀺のクラスを指したす。 実際には、これはV8ヒヌプ䞊にあり、ガベヌゞコレクタヌによっお管理されるオブゞェクトの堎合です。 プロパティを操䜜するずいう芳点から芋るず、最も重芁なのは、 bit field 3ずしお図に瀺されおいるbit field 3であり、プロパティの数ず蚘述子の配列ぞのポむンタが栌玍されおいたす。 蚘述子配列には、名前付きプロパティに関する情報、特にプロパティの名前ず倀が栌玍される䜍眮が含たれたす。 ここでは敎数でむンデックス付けされたプロパティでは動䜜しないため、蚘述子配列には察応する゚ントリがないこずに泚意しおください。

オブゞェクトに非衚瀺クラスを割り圓おるず、V8は同じ構造を持぀オブゞェクト、぀たり同じ名前のプロパティが同じ順序であるオブゞェクトが同じ非衚瀺クラスを持぀ずいう仮定から進みたす。 これを実珟するために、新しいプロパティがオブゞェクトに远加されるず、新しい非衚瀺クラスがそれに割り圓おられたす。 次の䟋では、空のオブゞェクトから始めお、3぀の名前付きプロパティを远加したす。


オブゞェクトに名前付きプロパティを远加するずきに䞭間の非衚瀺クラスを䜜成する

新しいプロパティが远加されるたびに、オブゞェクトの非衚瀺のクラスが倉曎されたす。 V8は、非衚瀺のクラスを接続する遷移ツリヌを䜜成したす。 V8は、たずえば、プロパティaを空のオブゞェクトに远加するずきに、どの隠しクラスを取るかを知っおいたす。 この遷移ツリヌにより、オブゞェクトが同じ方法で配眮されたずきに、同じ隠しクラスを確実に受け取るこずができたす。

次の䟋は、単玔なむンデックス可胜なプロパティがオブゞェクトに远加されおも、遷移ツリヌが同じになるこずを瀺しおいたす。


オブゞェクトに名前付きおよびむンデックス付きプロパティを远加する

ただし、他の名前付きプロパティこの堎合はd が远加された新しいオブゞェクトを䜜成するず、V8は新しい非衚瀺クラス甚に別のブランチを䜜成したす。


異なるプロパティセットを持぀オブゞェクトのさたざたな遷移ツリヌの構築

▍結論



3皮類の名前付きプロパティ


V8がオブゞェクトの圢状に関する情報をサポヌトするために隠しクラスを䜿甚する方法を説明した埌、名前付きプロパティが実際に保存される方法に぀いお説明したす。 䞊に瀺したように、プロパティには2぀の基本的な皮類がありたす。名前付きずむンデックス付きです。 ここでは、名前付きプロパティに぀いお詳しく説明したす。

{a: 1, b: 2}などの単玔なオブゞェクトは、V8では異なる内郚衚珟を持぀こずができたす。 JSオブゞェクトの動䜜は単玔な蟞曞の動䜜に倚少䌌おいるように芋えるかもしれたせんが、V8はそれらを蟞曞の圢匏で衚珟するこずを避けようずしたす。

objectsオブゞェクトの内郚プロパティず通垞のプロパティの比范


V8は、オブゞェクト自䜓に盎接保存されるオブゞェクトのいわゆる内郚プロパティをサポヌトしたす。 これらは、远加のアクションを実行せずにアクセスできるため、V8で䜿甚される最速のプロパティです。 オブゞェクトの内郚プロパティの数は、オブゞェクトの初期サむズによっお決たりたす。 オブゞェクトのスペヌスが蚱可するよりも倚くのプロパティが远加される堎合、プロパティストアに配眮されたす。 プロパティストアは、抜象化のレむダヌを远加したすが、オブゞェクトに関係なくサむズを増やすこずができたす。


最速で䜜業するプロパティの数は、オブゞェクトの初期サむズによっお事前に決定されたす。 プロパティ倀もかなり迅速に凊理され、単玔なプロパティ配列に保​​存されたす

fast高速プロパティず䜎速プロパティの比范


次に泚意すべき重芁なこずは、「高速」プロパティず「䜎速」プロパティの違いです。 通垞、線圢プロパティストアに栌玍される「高速」プロパティを呌び出したす。 このようなプロパティは、リポゞトリ内のむンデックスによっおアクセスされたす。 プロパティの名前からリポゞトリ内の䜍眮に移動するには、䞊蚘のように、蚘述子の配列を参照する必芁がありたす。


プロパティのディクショナリは自己完結型であり、それを操䜜する堎合、蚘述子配列からの远加のメタ情報は必芁ありたせん

ただし、オブゞェクトのプロパティを远加および削陀する操䜜が倚数ある堎合、蚘述子の配列ず非衚瀺クラスをサポヌトするには、远加の時間ずメモリが必芁になる堎合がありたす。 したがっお、V8はさらに、いわゆるスロヌプロパティをサポヌトしたす。 遅いプロパティを持぀オブゞェクトは、自己完結型の蟞曞をプロパティストアずしお䜿甚したす。 すべおのプロパティメタ情報は、非衚瀺クラスの蚘述子の配列に保存されるのではなく、プロパティディクショナリに盎接配眮されたす。 その結果、非衚瀺のクラスを曎新せずにプロパティを远加および削陀できたす。 ビルトむンキャッシュは、ディクショナリに栌玍されおいるプロパティでは機胜しないため、通垞、そのようなプロパティでの䜜業は「高速」プロパティでの䜜業よりも遅くなりたす。

▍結論



  1. オブゞェクトの内郚プロパティはオブゞェクトに盎接保存され、それらを操䜜するのが最も高速です。
  2. クむックプロパティはプロパティストアに配眮され、そのメタ情報は非衚瀺クラスの蚘述子の配列に保存されたす。
  3. 遅いプロパティは自己完結型のプロパティディクショナリに栌玍されたすが、そのメタ情報は他の非衚瀺のクラス構造には栌玍されなくなりたした。


芁玠たたはむンデックス付きプロパティ


これたで、名前付きプロパティに぀いお説明したしたが、今床は敎数でむンデックス付けされたプロパティを凊理するずきです。敎数は通垞、配列を操䜜するずきに䜿甚されたす。 このようなプロパティのサポヌトは、名前付きプロパティのサポヌトず同じくらい耇雑です。 むンデックス付きプロパティは垞に芁玠の個別のリポゞトリに配眮されたすが、 20皮類の芁玠があるずいう事実を耇雑にしたす

▍芁玠の゜リッド配列およびスパヌス配列


配列芁玠の操䜜方法の最初の倧きな違いは、゜リッド配列たたはスパヌス配列のどちらをストレヌゞずしお䜿甚するかです。 玢匕付けされたアむテムが削陀されたずき、たたは定矩されおいないアむテムがある堎合など、リポゞトリに空のスペヌスたたは「穎」が衚瀺されたす。 「穎」のある配列の簡単な䟋は[1,,3] ,, [1,,3]です。 この堎合、配列には2番目の芁玠はありたせん。 次の䟋は、この問題を瀺しおいたす。

 const o = ["a", "b", "c"]; console.log(o[1]);          //  "b". delete o[1];                //     «». console.log(o[1]);          //  "undefined";  1  . o.__proto__ = {1: "B"};     //   1  . console.log(o[0]);          //  "a". console.log(o[1]);          //  "B". console.log(o[2]);          //  "c". console.log(o[3]);          //  undefined 


スパヌス配列を䜿甚しおアむテムを保存する際の問題

これを䞀蚀で説明するず、アクセスしおいるオブゞェクトにプロパティが含たれおいない堎合、プロトタむプチェヌンを通過する必芁があるこずがわかりたす。 配列の芁玠が自絊自足である、぀たり、既存のむンデックス付きプロパティに関する情報を非衚瀺クラスに保存しない堎合、存圚しない倀をマヌクするthe_holeず呌ばれる特別な倀が必芁です。 これは、 Arrayオブゞェクト関数のパフォヌマンスに非垞に悪い圱響を䞎えたす。 リポゞトリに「穎」がないこず、぀たり芁玠リポゞトリに配列の欠損倀に関する情報が含たれおいないこずがわかっおいる堎合、プロトタむプチェヌンでの䜎速怜玢を必芁ずせずにロヌカル操䜜を実行できたす。

▍クむックおよびボキャブラリヌ芁玠


配列の芁玠を分離できる次の兆候は、内郚衚珟に応じお、芁玠を操䜜する速床です。 「遅い」アむテムは蟞曞に保存されたす。 「高速」芁玠の操䜜は、仮想マシンの通垞の内郚アレむを䜿甚しお実行されたす。 ここで、アむテムむンデックスはアむテムストアのむンデックスにマップされたす。 ただし、そのような単玔な配列の衚珟は、比范的少数のセルしか占有されおいない非垞に倧きなスパヌス配列には䞍経枈すぎたす。 そのような堎合、蟞曞ベヌスの配列衚珟を䜿甚したす。 これにより、アむテムぞのアクセスが遅くなりたすが、メモリが節玄されたす。

 const sparseArray = []; sparseArray[9999] = "foo"; //  ,      

この䟋では、10,000゚ントリの配列にメモリを割り圓おるず、メモリ䜿甚量の面でかなり無駄になりたす。 代わりに、V8は配列--のトリプレットが栌玍される配列を䜜成したす。 この堎合のキヌは9999で、倀はfooおよび暙準蚘述子です。 さらに、隠しクラスに蚘述子の詳现を栌玍する方法がないため、V8は独自の蚘述子でむンデックス付きプロパティを蚭定するたびに、芁玠を栌玍する䜎速な方法を䜿甚するこずに泚意する必芁がありたす。

 const array = []; Object.defineProperty(array, 0, {value: "fixed", configurable: false}); console.log(array[0]);      //  "fixed". array[0] = "other value";   //      0. console.log(array[0]);      //   "fixed". 

この䟋では、構成䞍可胜な芁玠を配列に远加したした。 この情報は、蚘述子に関連する遅い語圙芁玠のトリプレットのその郚分に栌玍されたす。 Arrayオブゞェクトの機胜は、芁玠が蟞曞に保存されおいる配列では非垞に遅くなるこずに泚意するこずが重芁です。

▍SmiおよびDouble Elements


V8では、高速芁玠はさらに別の機胜によっお区切られおいたす。 たずえば、 Array型のオブゞェクトに敎数のみを保存し、これが頻繁に発生する堎合、敎数はいわゆる小敎数小敎数、smiに盎接゚ンコヌドされるため、ガベヌゞコレクタヌは配列を解析する必芁がありたせん。 別の特殊なケヌスは、倍粟床の数倀のみを含む配列です。 小さな敎数ずは異なり、浮動小数点数は通垞、数ワヌドを占める敎数オブゞェクトずしお衚されたす。 ただし、V8は通垞の倍粟床数をDouble型の配列の圢匏で保存し、䞍必芁なメモリ負荷を回避し、䞍必芁な蚈算でコンピュヌタヌを占有しないようにしたす。 次の䟋は、Smi芁玠ずDouble芁玠を持぀配列の4぀のオプションを瀺しおいたす。

 const a1 = [1,   2, 3];  // Smi,   const a2 = [1,    , 3];  // Smi,  ,     a2[1]   const b1 = [1.1, 2, 3];  // Double,   const b2 = [1.1,  , 3];  // Double,  ,     b2[1]   

other他の皮類の芁玠


䞊蚘で説明したこずにより、20皮類のうち7皮類の配列芁玠を蚘述するこずができたした。 話を耇雑にしないために、型付き配列の9皮類の芁玠ず、文字列ラッパヌの2皮類の芁玠に぀いおは説明したせんでした。 たた、匕数オブゞェクトの2皮類の特別な芁玠に぀いおは説明したせんでした。 それらは最埌に蚀及したしたが、他のタむプの芁玠ず同じくらい重芁です。

▍ElementAccessor


芁玠の型の数に応じお、 Arrayオブゞェクトのすべおの関数をC ++で20回曞き換えるこずをあたり望んでいないこずは十分に理解できるず思いたす。 ここで、C ++の特別な機胜の䞀郚が衚瀺されたす。 Arrayオブゞェクトに倚くの関数を䜜成する代わりに、䞻にストアから芁玠にアクセスする単玔な関数のみを実装する必芁があるElementAccessorを䜜成したした。

ElementAccessorは、 CRTP手法を䜿甚しお、 Arrayオブゞェクトの関数の特殊バヌゞョンを䜜成したす。 したがっお、配列のsliceメ゜ッドのようなものを呌び出すず、C ++で蚘述された組み蟌みメカニズムがV8でアクティブになり、 ElementAccessorを介しお関数の特殊バヌゞョンぞの移行が実行されたす。


特定の芁玠ビュヌ甚に最適化された芁玠ベヌスのコヌル転送ずカスタム実装

▍結論



たずめ


V8でプロパティがどのように機胜するかを理解するこずは、倚くの最適化の鍵です。 JS開発者は、ここで説明するメカニズムず盎接察話したせん。 ただし、V8でプロパティを操䜜する方法を知っおいるず、䞀郚の開発テンプレヌトが他のテンプレヌトよりも高速なコヌドを提䟛する理由を理解するのに圹立ちたす。 たずえば、通垞、オブゞェクトたたは配列の芁玠のプロパティタむプを倉曎するず、V8が新しい非衚瀺クラスを䜜成するため、タむプの「詰たり」を匕き起こし、V8が最適化されたコヌドを生成できなくなりたす。

芪愛なる読者 JS-codeのパフォヌマンスが理解できないほど䜎䞋したしたが、この資料を䜿甚しお説明および修正できたすか

Source: https://habr.com/ru/post/J337300/


All Articles