🔩

Javascriptのことを調べていたら「ランタイム」について知らな過ぎたので調べた

2024/06/18に公開

この度、株式会社天地人エンジニアチームでは、念願のエンジニア技術ブログの立ち上げ~運用体制の整備が整いました。記念すべき第一回を担当するのは、Webアプリケーションエンジニア兼エンジニアリングマネージャの高瀬(@k_tacafe)です。

今回のテーマは「ランタイム」です。つい先日、Software Design 2024年6月号[実証]Bun 次世代JavaScriptランタイムの実体に迫る を読もうかと思った際に、JavaScriptのランタイムとかエンジンって何のことだっけ?いや、そもそも「ランタイム」ってちゃんと分かっていないよね??という想いが湧きあがりましたので、今日はランタイムについて基本的な部分を押さえていきたいと思います。

ランタイムを巡るあれこれ

ランタイムってそもそも?

ランタイム (英: runtime) または実行時は、計算機科学では、コンピュータ・プログラムのライフサイクルの最終フェーズであり、コードがコンピュータの中央処理ユニット(CPU)でマシンコードとして実行されている状態である。言い換えると、「ランタイム」はプログラムの実行フェーズである。(wikipedia

プログラムが実際に動いている時間のことですね。

Pythonで考えてみると、私たちが記述したスクリプトがインタープリタによってバイトコードに変換されて、そのバイトコードが実行されている、まさにその間の時間を指します。Pythonのプログラムを実際に動かすと遭遇するRuntimeErrorが指しているRuntimeです。

ランタイム「ライブラリ」?

ランタイムライブラリ(英: run-time library)は、標準Cライブラリなど、コンピュータプログラムの実行時(ランタイム)にメインプログラムと常に同時に存在して利用される前提のライブラリである。(wikipedia

ランタイムを支えるライブラリってことですね。C言語だとlibcとか、C++であればlibstdc++などといった代表的なものがあります。そっち方面をちょっと齧ったことがあれば目にしたことがあるかと思います。

そして「ランタイムを支える」というのは、具体的に以下のような機能を提供するということです。

  • メモリ管理
  • プロセス管理
  • 例外処理
  • 入出力処理
  • デバッグ支援
std::cout << "カレーにはナチュラル仕上げのモカが良く合いますよ\n"

こんな感じで、libstdc++ が入出力処理を提供してくれていますね。
CやC++のような静的型付言語でプログラムを作成する時は、コンパイルやビルド時に必要なランタイムライブラリを含めて準備する必要があるので馴染み深いと思います。

一方で、Webアプリケーションのような高水準なプログラムを動的型付言語で実装する仕事では、ランタイムライブラリに直接想いを馳せる機会は少ないかもしれません。ではPythonにとってのランタイムライブラリって何でしょう?

Pythonランタイムサービス を含む、Pythonの標準ライブラリのことを指す場合もあるし、Pythonインタープリタを指す場合もあれば、CPythonが依存する標準ライブラリを指す場合もあるようですね。会話の文脈によって指しているものが変わってくるような表現について、齟齬が出そうであればしっかり確認したほうが良さそうですね。

ランタイム「システム」?

ランタイムシステム(英: runtime system / run-time system)とは、主にコンピュータプログラムの実行モデルの一部を実装するものである。(wikipedia

実行モデル?

実行モデル (じっこうモデル、英: execution model)は、プログラミング言語の構成要素の一つ。プログラミング言語は、文法/構文と実行モデルで構成される。実行モデルは、言語の要素の動作を指定する。(wikipedia

コンピュータープログラムが動く仕組みに関する理論が「実行モデル」、その一部を実装したものが「ランタイムシステム」という事なんですね。なるほど。

実行モデルについてもっと詳しく追うと、恐らく深淵な世界を旅することになるので、今日のところはさらっと次に進みたいと思います。

プログラムが動作するために必要なあれこれをひっくるめたソフトウェアスタックが「ランタイムシステム」なのですが、人の世では「ランタイム」という言葉を広義に「ランタイムシステム」の意味で用いることが多いので、混乱してしまいますね。

ランタイム「エンジン」?

ランタイムエンジンについてChatGPTにさらっと教えてもらった 様々な書物、文献を巡る30年の旅から帰ってきた結果、

プログラムの実行を具体的に支援するためのソフトウェアコンポーネントです。ランタイムエンジンは、バイトコードや中間コード(中間言語)を実行するための環境を提供します。これにより、異なるプラットフォームでも一貫して動作するようになります。

という慧眼を得ました。

ここで、プログラムを動かす理論の実装である「ランタイムシステム」、プログラムの実行を支援してくれる「ランタイムエンジン」は機能的には同じようなもの?と混同しがちですが、stack overflowにあった質問スレッドに、納得感のある説明がありました。

Some authors seem to consider equivalent the expressions "runtime system" and "runtime engine", but maybe that could be avoided. Maybe "engine" should be reserved for frameworks a little higher in the software stack, closer to the application layer. For instance, a game engine. Or maybe a database engine.
和訳: 一部の著者は、「ランタイム・システム」と「ランタイム・エンジン」という表現を同等に考えているようだが、それは避けるべきかもしれない。「エンジン」は、ソフトウェア・スタックのもう少し上、アプリケーション層に近いフレームワークのために予約されるべきかもしれない。例えば、ゲームエンジン。あるいはデータベース・エンジンとか。

ランタイムシステムの上流部分(抽象度が高い部分)で「中間コードに落とし込んでくれるやつ」と把握すれば整理しやすいのかもしれませんね。Java, JavaScript, Ruby, Pythonなど、実行環境に応じたコンパイルが不要なのはこういった仕組みが備わっているからですね。

全体的にはこんなイメージになりました。

各プログラミング言語のランタイムシステムに想いを馳せてみよう

「ランタイム」やそれを支える概念について少しだけ整理できたところで、プログラミング言語ごとのランタイムシステムについて、ざっくりまとめておきたいと思います。

言語 ランタイムシステムの概要・特徴など
C++ - 動作環境に応じたコンパイル & 実行ファイルによって動作するため、ランタイムエンジン上で動作するわけではない(ランタイムエンジンはない)
- stdlibc++などのランタイムライブラリがある
Rust - C++同様ランタイムエンジンはない
- io-uring, tokio-uring, async-stdなどの非同期処理を行うランタイムライブラリがある(なんか聞いたことある)
Go - C++同様ランタイムエンジンはない
- 「Goランタイム」がgoroutine(非同期処理)やガベージコレクションなど、様々な機能(ライブラリ)を備えている
Java - 静的型付言語ではあるものの、Java Virtual Machine (JVM) というJavaのバイトコードを実行するランタイムエンジン上で動作する
- プラットフォームに依存せずにJavaプログラムを実行できる
C# - 静的型付言語ではあるものの、.NETランタイムエンジン(CLR: Common Language Runtimeとも呼ばれている)が存在する
- CLRはC#だけでなく、VB.NET, F#などが動作でき、他言語からの実装としてC++/CLI, IronPython, IronRubyなどがある
- CLR上で動くC++,Python,Rubyなどの実装があり、それらを利用すると例えばPythonから.NETのライブラリを直接呼び出せたりする
Python - CPython: 最も一般的なPythonのランタイムエンジン
- PyPy: JITコンパイラを搭載した高速なPythonランタイムエンジン
- Jython: Javaプラットフォーム(JVM)上で動作するPythonランタイムエンジン(多分ジャイアンの親戚
Ruby - MRI (Matz's Ruby Interpreter): 最も一般的なRubyのランタイムエンジン
- JRuby: Javaプラットフォーム上で動作するRubyランタイムエンジン
- TruffleRuby: GraalVM上で動作する高性能なRubyランタイムエンジン

では、改めてJavaScriptランタイムって?

JavaScriptで記述されたプログラムが実行されている時間を指す厳密な「ランタイム」の事ではなく、Webブラウザやサーバー上でJavaScriptコードを実行するためのソフトウェアスタックをまとめて「JavaScriptランタイム」と一般的に呼ばれているようです。

ランタイムエンジンを含めた全体を表す言葉なので「JavaScriptランタイムシステム」と呼んだ方が適切なのかもしれませんが、全体を包括した概念としては「JavaScriptランタイム環境(JavaScript Runtime Environments)」という言葉が用いられる方が多い印象があります。

JavaScriptランタイムには以下のようなものがあります。

名前 特徴
Node.js V8エンジンを使用し、JavaScriptをサーバーサイドで実行するためのAPIやライブラリを提供する
DENO V8エンジンを使用し、JavaScriptとTypeScriptの実行環境を提供する(Rust実装)
BUN JavascriptCoreエンジンを使用し、JavaScriptとTypeScriptの実行環境を提供する(Zig実装)

なるほど、JavaScriptランタイムは、それぞれの実装ごとに異なるランタイムエンジンを採用しているんですね。では、ランタイムエンジンにはどのような種類があるのでしょうか?

名前 開発元 主な使用用途 特徴
V8 Google Chrome, Node.js 高速な実行速度、Just-In-Time (JIT) コンパイル
SpiderMonkey Mozilla Firefox ECMAScript標準のリファレンス実装、デバッグ機能
JavaScriptCore Apple Safari 高度に最適化されたコンパイラ、セキュリティ機能
Chakra Microsoft 古いバージョンのEdge モジュール化された設計、良好なパフォーマンス
Nashorn Oracle Javaアプリケーション Javaとのシームレスな統合、スクリプトエンジン

Chrome, Firefox, Safariなど、有名どころ各社(+オープンソースプロジェクト)が開発している代表的なWebブラウザ製品ごとに、エンジンも異なるんですね。

それでは、基本的な理解が整ったところで、Software Design 2024年6月号[実証]Bun 次世代JavaScriptランタイムの実体に迫る を自信をもって読んでいきたいと思います。

おわりに

クラウド環境の高機能化が進んでいる昨今、サーバーレス + IaCなどの力を使って、高水準なプログラムコードの力だけでアプリケーションからインフラまで一気通貫で開発・運用することが可能となってきました。

スモールスタート & ハイスピードな進め方が期待されるような開発チームでは、各メンバーが得意領域で活躍して行くことが重要ですが、Frontend / Backend / Infrastructure まで手広くフォローできる「スキル幅」も以前より求められる傾向が強まってきたのではないでしょうか。

天地人エンジニアチームでは、メンバーそれぞれの個性や強みを活かしつつ、仕事を通じてスキルの「幅」と「深さ」の両面でどんどん成長していけるようなチーム体制・文化作りを目指しています。技術的な知見だけでなく、チームが成長していく姿、面白い取り組みなどを含めて天地人エンジニアブログで発信していけるよう、今後とも励んでいきたいと思います。

お読みいただきありがとうございました。


株式会社天地人では、人工衛星などの宇宙ビッグデータを活用し、地球規模の課題に取り組むためのオンラインGISプラットフォーム天地人コンパスを開発しています。

私たちと一緒に天地人コンパスを開発してくれる仲間を募集しております。ご興味のある方は以下のページよりエンジニアリングの募集の求人にてご確認下さい。

https://www.wantedly.com/companies/company_5025838/projects

Discussion