SharedArrayBuffer

SharedArrayBuffer オブジェクトは、固定長の生バイナリデータバッファーのジェネリックを表すために使用されます。ArrayBuffer オブジェクトと似ていますが、こちらは共有メモリー上にビューを生成するために使用されます。 ArrayBuffer と異なり、SharedArrayBuffer は分離できません。

解説

メモリーの割り当てと共有

クラスター内のあるエージェントから別のエージェント (エージェントとは、ウェブページのメインプログラムまたはそのウェブワーカーのひとつ) へ、SharedArrayBuffer オブジェクトを使用してメモリーを共有するために、postMessage (en-US)構造化クローンを使用します。

構造化クローンアルゴリズムは SharedArrayBuffers と、SharedArrayBuffers にマッピングされた TypedArrays を受け入れます。どちらの場合も SharedArrayBuffer オブジェクトは受信者に転送されて、受信側のエージェントで新たなプライベートの SharedArrayBuffer オブジェクトになります (ArrayBuffer と同じように)。しかし、2 つの SharedArrayBuffer オブジェクトから参照される共有データブロックは同一のデータブロックであり、あるエージェントによるブロックへの副作用は、結果的に他方のエージェントからも見えます。

var sab = new SharedArrayBuffer(1024);
worker.postMessage(sab);

Atomic 操作による共有メモリーを更新や同期

共有メモリーは、ワーカー内でもメインスレッド内でも同時に生成や更新ができます。システム (CPU、 OS、ブラウザー) によっては、変更がすべてのコンテキストに通知されるまでに少々時間がかかります。同期するためには、atomic 操作が必要です。

SharedArrayBuffer オブジェクトを使用する API

セキュリティの要件

共有メモリーと高解像度タイマーは、 Spectre の対策として 2018 年の初めに事実上無効化されました。 2020 年には、共有メモリを再び有効にするために、新しい安全なアプローチが標準化されました。いくつかのセキュリティ対策を施すことで、 postMessage()SharedArrayBuffer オブジェクトに対して例外を発生しなくなり、スレッド間の共有メモリが利用できるようになります。

基本的な要件として、文書が安全なコンテキストにある必要があります。

最上位の文書では、サイトにオリジン間の分離性を持たせるため、次の2つのヘッダーを設定する必要があります。

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

オリジン間の分離が成功したかどうかは、ウィンドウとワーカーのコンテキストで利用できる crossOriginIsolated (en-US) プロパティを使って確認することができます。

if (crossOriginIsolated) {
  // Post SharedArrayBuffer
} else {
  // Do something else
}

また、ブラウザー (Firefox 79など) で展開され始めている共有メモリーの計画的な変更 (en-US)も参照してください。

SharedArrayBuffer の生成には new 演算子が必要

SharedArrayBuffer コンストラクターは、new 演算子で呼び出す必要があります。new 演算子なしで関数として SharedArrayBuffer コンストラクターを呼び出すと、TypeError が発生します。

var sab = SharedArrayBuffer(1024);
// TypeError: calling a builtin SharedArrayBuffer constructor
// without new is forbidden
var sab = new SharedArrayBuffer(1024);

コンストラクター

SharedArrayBuffer()
新しい SharedArrayBuffer オブジェクトを生成します。

インスタンスプロパティ

SharedArrayBuffer.prototype.byteLength
配列の大きさをバイト数で表します。これは配列が構築されたときに確立され、変更することはできません。読み取り専用です。

インスタンスメソッド

SharedArrayBuffer.prototype.slice(begin, end)
新しい SharedArrayBuffer を作成し、その中身をこの SharedArrayBufferbegin の位置から end の位置の一つ手前までのバイトをコピーして返します。 begin または end が負の数の場合は、配列の先頭からではなく末尾からの位置で参照します。

新しい SharedArrayBuffer の生成

var sab = new SharedArrayBuffer(1024);

SharedArrayBuffer の分割

sab.slice();    // SharedArrayBuffer { byteLength: 1024 }
sab.slice(2);   // SharedArrayBuffer { byteLength: 1022 }
sab.slice(-2);  // SharedArrayBuffer { byteLength: 2 }
sab.slice(0, 1); // SharedArrayBuffer { byteLength: 1 }

WebGL バッファー内での使用

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, sab, gl.STATIC_DRAW);

仕様書

Specification
ECMAScript Language Specification (ECMAScript)
# sec-sharedarraybuffer-objects

ブラウザーの互換性

BCD tables only load in the browser

関連情報