---
title: "V8 Isolateとは？Contextとの違い・起動とメモリの実測とCloudflareの分離設計【2026年11月】"
url: "https://www.issoh.co.jp/tech/details/12608/"
published: 2026-06-17
updated: 2026-11-09
categories: ["JavaScript"]
publisher: "株式会社一創"
---

# V8 Isolateとは？Contextとの違い・起動とメモリの実測とCloudflareの分離設計【2026年11月】

V8 Isolate（アイソレート）は、JavaScriptエンジンV8の状態を丸ごと分けた実行単位です。Isolateごとにヒープとガベージコレクタが独立しているため、1つのOSプロセスの中に、互いのオブジェクトに触れられない実行環境を多数並べられます。Cloudflare Workersがコンテナを使わずに多数の顧客コードを同じマシンで動かせるのは、この仕組みによります。本記事では、V8公式APIの定義から始めて、Contextとの違い、Node.jsでの3つの分離手段、起動時間とメモリの実測、Cloudflare Workersの制約、Isolateだけでは足りない防御までを順に説明します。コード例と計測値は Homebrew版の node v26.5.0（V8 14.6）、isolated-vm 7.0.2、workerd 1.20260730.1 で2026年11月9日に実行したものです。

## まとめ：V8 Isolateは状態を分けた実行単位、分離の強さはV8と周囲の防御次第

V8 Isolateは「V8エンジンの独立した1インスタンス」です。Isolateをまたいでオブジェクトを渡すことはできず、ヒープもガベージコレクションも別々に動きます。その内側にグローバル環境を表すContextが1つ以上入ります。Node.jsの `vm.createContext()` が作るのはContextで、Isolateではありません。

軽さは手元のIntel Macで確かめました。Isolate＋Contextの生成と式の評価は中央値6.48ミリ秒で、Node.js子プロセスの起動から終了までの234.7ミリ秒の約36分の1でした。計測区間が異なるため、純粋な起動時間の比ではありません。1個あたりのメモリ増分は1.19MBで、Node.jsプロセス（32MB）の約27分の1でした。一方で、Isolateの境界はV8というソフトウェアの正しさに依存します。Cloudflareはプロセス分離・seccomp・24時間未満のパッチ適用・時刻の固定を重ねており、自前で信頼できないコードを動かすなら同じ種類の防御を自分で用意します。

## V8 Isolateの定義：V8公式APIの記述とスレッドの制約

[V8のC++ APIリファレンス](https://v8.github.io/api/head/classv8%5F1%5F1Isolate.html)は、`v8::Isolate` を次のように定義しています。

> `Isolate represents an isolated instance of the V8 engine. V8 isolates have completely separate states. Objects from one isolate must not be used in other isolates.`

「完全に分かれた状態」とは、JavaScriptのオブジェクトを置くヒープ、ガベージコレクタ、組み込みオブジェクトの一式がIsolateごとに別という意味です。あるIsolateで作った配列の参照を別のIsolateへ持ち込むことはAPI上禁止されています。値を渡すときは、構造化複製のようにコピーするか、埋め込み側（エンベッダー）が用意した仲介の仕組みを通します。

同じリファレンスには、スレッドとの関係も書かれています。エンベッダーは複数のIsolateを作って複数スレッドで並列に動かせますが、`An isolate can be entered by at most one thread at any given time.` の通り、1つのIsolateに同時に入れるスレッドは1本だけです。複数スレッドで同じIsolateを使うなら `Locker` で排他します。並列性はIsolateの数で稼ぐ設計です。

埋め込み側から見ると、Isolateは明示的に作って破棄する対象です。V8公式サンプルの [hello-world.cc](https://github.com/v8/v8/blob/main/samples/hello-world.cc) は、`Isolate::New` で作り、`Isolate::Scope` で入り、`HandleScope` を積んでから `Context::New` と `Context::Scope` で実行環境に入ります。あとは `Script::Compile` と `Run` で実行し、最後に `isolate->Dispose()` で破棄します。Node.jsもChromeもCloudflare Workersも、V8をこの順序で使うエンベッダーです。

## IsolateとContextの違い：ヒープの共有範囲とvmモジュールの落とし穴

[v8::Context](https://v8.github.io/api/head/classv8%5F1%5F1Context.html) は、V8のリファレンスで `A sandboxed execution context with its own set of built-in objects and functions.` と説明されています。Contextは独自の `globalThis`、`Object`、`Array` などの組み込み一式を持つグローバル環境です。ただしContextはIsolateの中に作られ、同じIsolateの中のContext同士はヒープを共有します。ブラウザでiframeごとに別の `window` があっても、同一オリジンなら互いのオブジェクトを参照できるのはこの構造によります。

| 単位      | ヒープ         | グローバル環境     | 並列実行        | Node.jsでの作り方               |
| ------- | ----------- | ----------- | ----------- | -------------------------- |
| Context | Isolate内で共有 | 独立          | 不可（同じスレッド）  | `vm.createContext()`       |
| Isolate | 独立          | 中のContextごと | Isolate単位で可 | Worker Threads・isolated-vm |
| OSプロセス  | 独立          | 独立          | 可           | `child_process`・`cluster`  |

この違いが実害になるのが、`vm` モジュールを「サンドボックス」だと誤解する場面です。空のオブジェクトからContextを作っても、Context内のコードはコンストラクタをたどってホスト側の `Function` に届き、そこから `process` を取り出せます。

```
import vm from 'node:vm';

const ctx = vm.createContext({});
const p = vm.runInContext(
  "this.constructor.constructor('return process')()",
  ctx
);
console.log(p.pid === process.pid); // true
console.log(typeof p.getBuiltinModule); // 'function'
```

隔離したはずのContextからホストの `process` が返り、`process.getBuiltinModule()` 経由で `fs` や `child_process` も読み込めます。[Node.js公式ドキュメント](https://nodejs.org/api/vm.html)も `vm` の項で `The node:vm module is not a security mechanism. Do not use it to run untrusted code.` と警告しています。`vm` はテンプレート評価のように、信頼できるコードのグローバルを分けたいときの道具です。

## Node.jsでコードを分離する手段：vm・Worker Threads・isolated-vmの比較

Node.jsのメインスレッドは1つのIsolateで動きます。Node.jsそのものの仕組みは[Node.jsの仕組みと版の選び方](/tech/details/17433/)に譲り、ここでは前章のvmに加えてIsolateを追加する2つの手段を取り上げます。

### Worker Threads：resourceLimitsによるヒープ上限の設定

`node:worker_threads` の `Worker` は、別スレッドに新しいJSエンジンのインスタンスを立ち上げます。Worker内では `require` も `fs` も使えるので、隔離ではなく並列計算のための仕組みです。それでも `resourceLimits` でヒープの上限を切れる点は、暴走したコードからメインスレッドを守るのに役立ちます。

```
import { Worker } from 'node:worker_threads';

const w = new Worker(
  'const a = []; while (true) { a.push(new Array(1e5).fill(1)); }',
  { eval: true, resourceLimits: { maxOldGenerationSizeMb: 16 } }
);
w.on('error', (e) => console.log(e.code));  // ERR_WORKER_OUT_OF_MEMORY
w.on('exit', (code) => console.log(code));  // 1
```

Workerは `ERR_WORKER_OUT_OF_MEMORY` で終了し、メインスレッドは動き続けました。ただし[公式ドキュメント](https://nodejs.org/api/worker%5Fthreads.html)のとおり、この上限はJSエンジンのヒープだけに効き、`ArrayBuffer` などの外部データは対象外です。プロセス全体がメモリ不足になれば、上限を設定していてもプロセスごと落ちます。

### isolated-vm：転送可能な値とmemoryLimit・timeoutによる実行制限

[isolated-vm](https://github.com/laverdet/isolated-vm)は、V8の `Isolate` インターフェースをNode.jsから直接使えるようにするネイティブアドオンです。作ったIsolateの中にはNode.jsのAPIが一切ありません。READMEの指示どおり `node --no-node-snapshot` で起動して次のコードを実行すると、コメントの結果になりました。

```
import ivm from 'isolated-vm';

const iso = new ivm.Isolate({ memoryLimit: 8 });  // MB
const ctx = await iso.createContext();

console.log(await ctx.eval('typeof process'));    // 'undefined'

await ctx.global.set('copied', { a: 1 }, { copy: true });
console.log(await ctx.eval('copied.a'));          // 1

try {
  await ctx.global.set('raw', { a: 1 });
} catch (e) {
  console.log(e.message);  // A non-transferable value was passed
}

await ctx.global.set('hostFn', () => 'from host');
console.log(await ctx.eval('hostFn()'));          // 'from host'

try {
  await ctx.eval('while (true) {}', { timeout: 50 });
} catch (e) {
  console.log(e.message);  // Script execution timed out.
}

try {
  await ctx.eval('const a = []; while (true) { a.push(new Array(1e5).fill(1)); }');
} catch (e) {
  console.log(e.message);  // Isolate was disposed during execution due to memory limit
}
console.log(iso.isDisposed);  // true
```

この例の通常のオブジェクトリテラルは、`copy: true` などの転送方法を指定しなければ拒否されます。これがIsolateの「オブジェクトを持ち込めない」という性質の現れです。一方、関数は `Callback` に自動で変換され、隔離側から普通の関数として呼べました。関数の中身はホスト側で動くので、渡した関数がそのまま隔離の出口になります。渡す関数は、引数を検証して必要な処理だけをする小さなものに限ります。

メモリ超過のあとIsolateは使えなくなるので、実運用では実行のたびに作り直すか、破棄を検知して再生成します。`memoryLimit` については、READMEが `A determined attacker could use 2-3 times this limit` と書いています。悪意のあるコードでは、8MBと指定しても16〜24MB程度を消費し得ます。memoryLimitは厳密な上限ではないため、この範囲を保証された最大値とは扱わず、別プロセス側にもメモリ制限を設けてください。

導入前に確認すべき制約もあります。READMEはプロジェクトを `maintenance mode` と明記し、技術的に可能な限りサポートを続けるとしています。対応表はNode.js 22が5.xか4.x、24が6.xか5.x、26が7.xで、奇数版のNode.jsはサポートしていません。[npmの最新版7.0.2](https://www.npmjs.com/package/isolated-vm)（2026年10月30日公開）は `engines` が `node >=24.0.0` です。Node.js 20以降では `--no-node-snapshot` の指定が求められます。

READMEのSECURITY節は、`Reference` や `ExternalCopy` などのインスタンスを信頼できないコードへ渡すと、それを足がかりにホスト側のIsolateへ戻られると警告しています。隔離側に渡すのは、`copy: true` で複製した値と、検証済みの小さな関数だけにします。

### vm・Worker Threads・isolated-vmの選定基準：コードの信頼性とメモリ上限

| 観点          | vm              | Worker Threads   | isolated-vm   |
| ----------- | --------------- | ---------------- | ------------- |
| 分離の単位       | Context         | Isolate＋スレッド     | Isolate       |
| Node.js API | ホストに到達可能        | 使える              | 無い            |
| メモリ上限       | 無し              | `resourceLimits` | `memoryLimit` |
| 実行時間の上限     | `timeout`（同期のみ） | `terminate()`    | `timeout`     |
| 追加の依存       | 無し              | 無し               | ネイティブビルド      |
| 向く用途        | 信頼済みコードの評価      | CPU負荷の並列化        | 第三者コードの実行     |

`vm` の `timeout` は既定で同期実行だけが対象で、`microtaskMode: 'afterEvaluate'` を指定するとマイクロタスクも時間制限に含まれます。判断の軸は、実行するコードを書いたのが誰かです。自社のコードを並列化したいならWorker Threads、利用者やLLMが書いたコードを動かすならisolated-vm、またはそれ以上に強い隔離を選びます。isolated-vmのREADME自身が、重要な基盤とは別のNode.jsプロセスで動かすよう勧めています。

## 起動時間とメモリの実測：Isolate・Worker・Node.jsプロセスの比較

[Cloudflareの公式ドキュメント](https://developers.cloudflare.com/workers/reference/how-workers-works/)は、Isolateの起動はコンテナや仮想マシン上のNodeプロセスのおよそ100倍速く、起動時のメモリ消費は1桁少ないと説明しています。数値の出どころは[2018年のCloudflareブログ](https://blog.cloudflare.com/cloud-computing-without-containers/)で、Isolateは5ミリ秒で起動し、コードを持たないNode.jsのLambdaが35MBを消費するのに対して、ランタイムを共有すると約3MBに下がると書かれています。同じ差を手元で確かめました。環境はIntel Core i9-9880H・macOS・node v26.5.0（他のワーカーが動く負荷のある状態）で、コンテナとマイクロVMは計測していません。

### 生成・実行時間：Isolateの生成・評価とNode.jsプロセスの起動・終了の比較

| 計測対象                                | 中央値（5回） | 1回の試行数 |
| ----------------------------------- | ------- | ------ |
| isolated-vmでIsolate＋Contextを作り1式を評価 | 6.48ms  | 100    |
| Workerを起動し最初のメッセージを受信               | 90.3ms  | 20     |
| `node -e 1` の子プロセス起動から終了まで          | 234.7ms | 20     |

Workerが90ミリ秒かかるのは、Isolateに加えてスレッドとNode.jsの実行環境（イベントループやモジュールローダー）を初期化するためです。2018年ブログの約100倍はNodeプロセスの起動との比較です。今回の約36倍は、Isolate＋Contextの生成・式の評価とNode.js子プロセスの起動から終了までの比較であり、同一の計測条件ではありません。倍率はハードウェアやNode.jsの版で変わるので、桁の目安として読んでください。

### メモリ：Isolate 1,000個で1個あたり1.19MB

公式ドキュメントの「1つのランタイムで数百から数千のIsolate」を確かめるため、1,000個のIsolateを同じプロセスに保持してRSS（物理メモリ使用量）の増分を測りました。

```
import ivm from 'isolated-vm';

const N = 1000;
const rss = () => process.memoryUsage().rss / 1048576;
const before = rss();
const kept = [];
for (let i = 0; i < N; i++) {
  const iso = new ivm.Isolate({ memoryLimit: 8 });
  const ctx = iso.createContextSync();
  ctx.evalSync('globalThis.x = 1');
  kept.push([iso, ctx]);
}
await new Promise((r) => setTimeout(r, 800));
console.log(((rss() - before) / N).toFixed(2), 'MB/isolate');
process.exit(0);
```

| 単位              | 1個あたりのRSS | 測り方             |
| --------------- | --------- | --------------- |
| Isolate＋Context | 1.19MB    | 1,000個を保持した増分   |
| Worker          | 11.4MB    | 50個を保持した増分      |
| Node.jsプロセス     | 32MB      | `node -p` の自己申告 |

上のコードは5回とも1.19MBで、同型のスクリプトを合わせた10回のうち1回だけ0.57MBでした。1,000個まで作っても1個あたりの生成時間は6.8〜7.0ミリ秒で、作るほど遅くなる傾向は見えません。1,000個の合計は約1.2GBです。公式の「数千個」は空のIsolateなら16GB級のマシンに収まりますが、これはコードもデータも持たないIsolateの値で、載せた分だけ増えます。

## Isolate・コンテナ・マイクロVMの分離境界と選び方

コンテナより強い隔離が必要で、Isolateより重くてもよい場合の選択肢がマイクロVMです。AWS LambdaはFirecrackerというマイクロVMで関数ごとにカーネルまで分けています。仕組みは[Firecracker（マイクロVM）の仕組み](/tech/details/15691/)、Lambda側の対策は[AWS Lambdaの仕組みとコールドスタート対策](/tech/details/15407/)で解説しています。

| 方式         | 分離の境界     | 動かせるもの          | 代表例                     |
| ---------- | --------- | --------------- | ----------------------- |
| V8 Isolate | V8のヒープ分離  | JavaScript・Wasm | Cloudflare Workers      |
| コンテナ       | カーネルの名前空間 | 任意のLinuxプロセス    | Docker・Kubernetes（runc） |
| マイクロVM     | ハイパーバイザー  | 任意のLinuxプロセス    | AWS Lambda（Firecracker） |

Isolateが使えないのは、ネイティブバイナリや任意の言語ランタイムを動かしたいときです。V8の中で動くのはJavaScriptとWebAssemblyだけなので、WebAssembly向けにビルドされていないネイティブ拡張や、特定のLinuxコマンドに依存する処理は載りません。中間の選択肢は[Kata ContainersとgVisor・runcの比較](/tech/details/15693/)を参照してください。

## Cloudflare WorkersでのIsolateの制約：再利用・128MB・起動

サーバー側でIsolateをマルチテナントの分離単位に使う代表例がCloudflare Workersです。Workers全体の料金や使い方は[Cloudflare Workersの対応言語・無料枠・料金](/tech/details/6760/)にまとめているので、ここではIsolate由来の制約だけを挙げます。

### グローバル変数の寿命：workerdでの再利用の確認

Workersのランタイムを公開した[workerd](https://github.com/cloudflare/workerd)を、miniflare 4.20260730.0 でローカルに立てて確かめました。同じスクリプトをWorker aとbとして読み込み、グローバル変数のカウンタとCPUループ中の時計を見ます。

```
import { Miniflare } from 'miniflare';

const script = `
let n = 0;
export default {
  async fetch(req) {
    if (new URL(req.url).pathname === '/clock') {
      const t0 = Date.now();
      for (let i = 0; i < 3e8; i++) {}
      return Response.json({ spinMs: Date.now() - t0 });
    }
    n++;
    return Response.json({ n });
  },
};`;

const base = { modules: true, script, compatibilityDate: '2026-08-01' };
const conf = {
  workers: [
    { name: 'a', ...base },
    { name: 'b', ...base },
  ],
};
const mf = new Miniflare(conf);
const a = await mf.getWorker('a');
const b = await mf.getWorker('b');
const get = async (w, p) => (await w.fetch('http://x' + p)).json();

for (let i = 0; i < 3; i++) console.log('a', await get(a, '/'));  // n: 1, 2, 3
console.log('b', await get(b, '/'));                              // n: 1
console.log(await get(a, '/clock'));                              // spinMs: 331

await mf.setOptions(conf);  // 同じ設定で読み込み直す
console.log('a', await get(await mf.getWorker('a'), '/'));        // n: 1
await mf.dispose();
```

Worker aのカウンタは1・2・3と増え、bは1から始まり、読み込み直すと1に戻りました。同じWorkerの複数リクエストが同じIsolateを再利用することはありますが、本番では同じIsolateへ届く保証はありません。Workerが異なればIsolateも分かれ、Isolateが作り直されれば状態は消えます。[公式ドキュメント](https://developers.cloudflare.com/workers/reference/how-workers-works/)は、Isolateが退去させられる理由としてマシンの資源不足、隔離を破ろうとする疑わしいスクリプト、個別のリソース上限の3つを挙げています。トップレベルに置くのは消えてもよいキャッシュだけにして、消えては困るデータはKV・D1・Durable Objectsへ置きます。

時計の結果には注意が要ります。[セキュリティモデルの文書](https://developers.cloudflare.com/workers/reference/security-model/)によれば本番のWorkersでは `Date.now()` は最後のI/Oの時刻を返し、実行中は進みません。ところがローカルのworkerdでは、CPUループの間に331ミリ秒進みました。処理時間を `Date.now()` の差で測るコードは、ローカルで動いて見えても、本番ではI/Oを挟まない区間の差が0になります。

### メモリとCPUの上限：128MBはIsolate単位

| 項目                 | Free  | Paid       |
| ------------------ | ----- | ---------- |
| HTTPリクエストあたりのCPU時間 | 10ms  | 既定30秒・最大5分 |
| メモリ（Isolateあたり）    | 128MB | 128MB      |
| Workerの起動時間        | 1秒    | 1秒         |

[上限の公式ページ](https://developers.cloudflare.com/workers/platform/limits/)によれば、128MBは呼び出し単位ではなくIsolate単位で、JavaScriptのヒープとWebAssemblyの割り当てを合算します。1つのIsolateが複数のリクエストを同時に処理するため、リクエストごとに大きなバッファを抱えれば、同時実行数に比例して上限に近づきます。超えると処理中のリクエストを終えてから新しいIsolateへ切り替わります。CPU時間には `fetch()` やKVの読み取りを待つ時間が入りません。起動時間の1秒はグローバルスコープの実行を含み、超えるとデプロイ時に `Script startup exceeded CPU time limit`（エラーコード10021）で拒否されます。

### コールドスタートの実体：ClientHello先読みとWorker sharding

Isolateの生成が数ミリ秒でも、生成そのものが無くなるわけではありません。Cloudflareは[2020年の発表](https://blog.cloudflare.com/eliminating-cold-starts-with-cloudflare-workers/)で、TLSの最初のパケットであるClientHelloを受けた時点で該当ホストのWorkerを読み込み始め、ハンドシェイクが終わる頃には準備を済ませる方式を説明しました。これが「0ms cold starts」の中身で、起動を消したのではなく前倒ししたものです。

[2025年の発表](https://blog.cloudflare.com/eliminating-cold-starts-2-shard-and-conquer/)ではWorker shardingが加わりました。データセンター内のサーバーのうち同じWorkerを温めている1台へ、一貫性ハッシュでリクエストを寄せる仕組みです。Enterpriseの通信のうちシャーディングされたのは約4%でしたが、Worker全体の退去率は10分の1に下がったと報告されています。アクセスが少ないWorkerほど別サーバーでの再生成が減る設計です。

### Isolateを実行単位にするサービスの変化：Vercel・Deno

Cloudflare以外の状況は2026年に大きく動きました。[VercelのEdge Runtime](https://vercel.com/docs/functions/runtimes/edge)の文書はNode.jsランタイムへの移行を勧め、Next.js 16.3以降は `runtime = 'edge'` の指定をサポートしないと書いています。単独製品のEdge Functionsも非推奨です。Deno Deploy Classicは[2026年7月20日での終了が告知](https://docs.deno.com/deploy/migration%5Fguide/)され、後継は[Runtimeの文書](https://docs.deno.com/deploy/reference/runtime/)で標準DenoをLinux microVM上で動かすと説明しています。その後継も[2026年10月の発表](https://deno.com/blog/cloudflare)で6か月後の終了が告げられました（[Deno Deploy終了と移行手順](/tech/details/18318/)）。Isolate前提で書いたコードは、移行先のランタイムを先に確かめてください。共通APIの標準化は[WinterTC（Ecma TC55）とECMA-429](/tech/details/5260/)で扱っています。

## Isolateだけでは足りない分離境界：Cloudflareの防御層とV8 Sandbox

Isolateの境界は、V8が正しく動くことを前提にしています。V8にメモリ破壊のバグが1つあれば、同じプロセス内の他のIsolateのメモリに届く可能性があります。加えて[V8チームの論文（arXiv:1902.05178）](https://arxiv.org/abs/1902.05178)はSpectreを言語の仕組みだけでは防げないと結論しています。Cloudflareの[セキュリティモデルの文書](https://developers.cloudflare.com/workers/reference/security-model/)は、この前提で次の層を重ねていると説明します。

| 防御層          | 内容                   | 想定する脅威        |
| ------------ | -------------------- | ------------- |
| cordon       | 信頼度別にランタイムを分ける       | V8のゼロデイ       |
| プロセスのサンドボックス | 名前空間とseccomp         | 隔離の突破後の横展開    |
| パッチ適用        | V8修正から24時間未満で反映      | 既知のV8脆弱性      |
| 時刻とスレッドの制限   | `Date.now()` を実行中は固定 | Spectre系の計時攻撃 |
| 別プロセスへの退避    | デバッガ接続時などに適用         | 検査が薄いAPIのバグ   |

cordonの例として公式ドキュメントが挙げるのは、無料プランの利用者がEnterprise契約の顧客と同じプロセスに載らないことです。プロセス全体には、空のファイルシステムとseccompでファイル操作のシステムコールをすべて禁止する第2層のサンドボックスがかかり、外部との通信はUNIXドメインソケット経由で別プロセスが仲介します。

### V8 SandboxとNode.js公式ビルドの差

V8自身の対策が[V8 Sandbox](https://v8.dev/blog/sandbox)です。V8のメモリ破壊が同じプロセスの他の領域へ波及するのを防ぐ仕組みで、2024年4月に実験段階を終えました。有効化はビルド時の `v8_enable_sandbox` で決まり、実行時には切り替えられません。Cloudflareは[2025年9月のブログ](https://blog.cloudflare.com/safe-in-the-sandbox-security-hardening-for-cloudflare-workers/)で、V8 Sandboxに加えて、CPUのメモリ保護キーをIsolateごとに割り当てる変更をV8へ入れたと説明しています。約12種類のキーをランダムに配るため、別のIsolateのヒープを読もうとする攻撃は約92%の確率でハードウェアの例外で止まります。V8 Sandbox内のメモリ破壊に限る脅威モデルでは、キーを規則的に循環させ、同じキーのサンドボックスが32GiB以内に並ばないようにしています。

nodejs.orgが配布する v26.5.0 と v26.13.0（macOS x64）の `process.config.variables` を見ると、`v8_enable_sandbox` も `v8_enable_pointer_compression` も0でした。今回確認したNode.js公式配布のmacOS x64版では、isolated-vmを使ってもV8 Sandboxの層は加わりません。有効・無効はNode.jsのビルド設定で確認してください。

### isolated-vm単体で動かしてよい範囲の判断

isolated-vmを1つ入れただけのNode.jsサーバーで、不特定多数が書いたコードを動かすべきではありません。isolated-vmが提供するのはV8のヒープ分離だけで、表のどの層も含まないからです。社内の限られた利用者が書くスクリプトや、人がレビューしてから実行するコードなら許容できます。外部に公開するサービスでは、別プロセス化と、そのプロセスへのseccompやコンテナによる制限を組み合わせてください。[workerd](https://github.com/cloudflare/workerd)のREADMEも `workerd is not a hardened sandbox` と明記し、悪意のあるコードは仮想マシンなどの内側で動かすよう求めています。

V8の更新を即日で取り込めない体制なら、マイクロVMを選びます。Isolateの外側に置く層の設計はインフラの仕事で、自社サービスとして実行基盤を組む場合は[AWS・Google Cloud・Azureのインフラ構築](https://www.issoh.co.jp/service/system/aws/)でも支援しています。

## AI生成コードの実行基盤：Cloudflare Dynamic Workersの仕組みと料金

CloudflareはLLMが書いたコードの実行先としてIsolateを打ち出しています。[2026年3月24日](https://developers.cloudflare.com/changelog/post/2026-03-24-dynamic-workers-open-beta/)にDynamic Workersをオープンベータとして公開し、Workers Paidの利用者が使えるようにしました。Workerの中から、実行時に受け取ったコードで別のWorkerを起動できる機能です。呼び出し側はWranglerの設定で `worker_loaders` に `LOADER` バインディングを宣言し、`env.LOADER.load()` にコードを渡します。ローカルで再現するには、Miniflareをインポートし、次のコードを文字列の `script` として `new Miniflare({ modules: true, script, compatibilityDate: '2026-08-01', workerLoaders: { LOADER: {} } })` に渡します。作成したインスタンスの `dispatchFetch()` で呼び出し、最後に `dispose()` で終了します。

```
export default {
  async fetch(request, env) {
    const worker = env.LOADER.load({
      compatibilityDate: '2026-08-01',
      mainModule: 'src/index.js',
      modules: {
        'src/index.js': `
          export default {
            async fetch() {
              try {
                await fetch('https://example.com/');
                return new Response('reached');
              } catch (e) {
                return new Response('blocked: ' + e.message);
              }
            },
          };
        `,
      },
      globalOutbound: null,
    });
    return worker.getEntrypoint().fetch(request);
  },
};
```

応答は `blocked: This worker is not permitted to access the internet via global functions like fetch().` で始まるメッセージでした。`globalOutbound` を省略すると親Workerのネットワーク権限を継承するので、LLMのコードを動かすなら `null` を明示し、渡すバインディングも必要なものだけに絞ります。

[料金ページ](https://developers.cloudflare.com/dynamic-workers/pricing/)によれば、生成数の料金は月1,000個まで込みで、超過分は1個1日あたり0.002ドルです。これとは別にWorkersプランのリクエスト数・CPU時間の料金も適用され、Dynamic Workersでは初期化時のCPU時間も課金対象になります。IDとコードの組が同じなら1個と数えますが、`load()` はキャッシュせず呼び出しのたびに新しいWorkerを作るので、同じコードを繰り返すなら `get(id, callback)` を使います。隔離の中身は前章の防御層を持つWorkersのランタイムで、seccompやcordonを自分で組む必要はありません。ネイティブの実行環境が要るコードの受け皿は[Cloudflare Containers](/tech/details/18880/)、Dynamic Workerでアプリを隔離する実例は[Cloudflare OSとは：社内AIエージェント基盤の仕組み](/tech/details/18844/)で取り上げています。

## よくある質問

### V8 Isolateの読み方は？

「ブイエイト アイソレート」と読みます。isolateは英語で「隔離する」「隔離されたもの」を意味し、V8の中で状態を隔離した実行単位を指します。Cloudflareのドキュメントや英語の資料では複数形の V8 isolates もよく使われ、検索でも両方の表記が見られます。日本語の資料では「アイソレート」とカタカナで書くか、英語のまま書くのが一般的です。

### V8の「VM」は仮想マシンのことですか？

[V8の埋め込みガイド](https://v8.dev/docs/embed)は `An isolate is a VM instance with its own heap.` と書いていますが、ここでのVMはJavaScriptを実行する言語の仮想マシンです。OSを起動するKVMやVMwareの仮想マシンとは別物で、ハイパーバイザーの境界もありません。Isolate同士は同じOSプロセスの中で動き、分離はV8のソフトウェアが担います。

### IsolateはDartやFlutterのIsolateと同じものですか？

名前は同じですが別物です。[Dartの公式ドキュメント](https://dart.dev/language/concurrency)によれば、DartのIsolateは独自のメモリと単一スレッドのイベントループを持つ並行処理の単位で、メッセージ受け渡しで連携します。「状態を共有しない」という発想は似ていますが、V8のIsolateはV8エンジンのインスタンスを指す言葉で、Dartのランタイムとは実装が別です。

### Node.jsはいくつのIsolateを使っていますか？

1つのNode.jsプロセスのメインスレッドは1つのIsolateで動きます。Worker Threadsで `Worker` を作るたびに、別スレッドで新しいJSエンジンのインスタンスが加わります。`cluster` や `child_process` は別プロセスを起動するので、プロセスごとに別のV8が動きます。`vm.createContext()` はContextを増やすだけで、Isolateの数は変わりません。

### isolated-vmは本番環境で使えますか？

社内の限られた用途なら使えます。ただしREADMEはプロジェクトをmaintenance modeとしており、V8の更新に追従し続ける保証はありません。対応表にあるのはNode.js 22・24・26の偶数版で、Node.js 26なら7.x系を使います。不特定多数のコードを動かす用途では、isolated-vmだけに頼らず、別プロセス化とOS側の制限を組み合わせるか、マネージドの実行基盤を選びます。

## 関連記事

- [Cloudflare Workersとは？料金・無料枠・Workers Paidの中身と対応言語・使い方](/tech/details/6760/)
- [Firecracker（マイクロVM）とは？仕組み・KVMとの関係とgVisor・コンテナとの使い分けを実装者目線で解説](/tech/details/15691/)
- [Node.jsとは？仕組み・版の選び方・標準機能で動かす手順を実装目線で解説](/tech/details/17433/)
- [Cloudflare Containersとは？AIエージェントのサンドボックスを動かす手順と料金【2026年10月時点】](/tech/details/18880/)
- [Deno Deploy終了と移行手順：Cloudflare WorkersへのコードとKV・cronの移し方【2026年10月時点】](/tech/details/18318/)

---

出典: [V8 Isolateとは？Contextとの違い・起動とメモリの実測とCloudflareの分離設計【2026年11月】](<https://www.issoh.co.jp/tech/details/12608/>)（株式会社一創）
