57
27 学位 サーバサイド向け JavaScript 処理系の ためのマークスイープごみ集めの 設計と実装 Design and Implementation of a Mark Sweep Garbage Collection on a Server Side JavaScript Virtual Machine 1160326 2016 2 26 大学

サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

平成 27年度

学士学位論文

サーバサイド向け JavaScript処理系の

ためのマークスイープごみ集めの

設計と実装

Design and Implementation of a Mark Sweep

Garbage Collection on a Server Side JavaScript

Virtual Machine

1160326 高松 裕樹

指導教員 鵜川 始陽

2016年 2月 26日

高知工科大学 情報学群

Page 2: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

要 旨

サーバサイド向け JavaScript処理系の

ためのマークスイープごみ集めの

設計と実装

高松 裕樹

Webブラウザの高機能化に伴って,Webブラウザ上で動作するWebアプリケーションが

普及している.Webアプリケーションは,Webブラウザ上で JavaScriptのプログラムとし

て動作し,Webサーバ上のプログラムと通信しながら高度なサービスを提供する形態をと

る.近年,Webアプリケーションのサーバ側のプログラムの開発言語として JavaScriptが

普及してきている.そのため,サーバ上で動作する JavaScript(サーバサイド JavaScript)

の処理系の高速化の研究が盛んに行われている.サーバ上では大規模なプログラムを動かす

ことが多いと予想される.その際にプログラムの処理時間に大きく影響を与えるのが,ガ

ベージコレクション(以下,GC)である.GCとは,メモリ領域上のプログラムが利用し

なくなった領域を回収して,再度利用可能にする処理である.GC実行中はプログラムの処

理が停止しているため,GCの時間はそのままプログラムの実行時間に影響を与える.本研

究では,サーバサイド向け JavaScript 仮想機械である SSJSVM の GC について,他の処

理系に比べて高速かどうか調べた.その結果,既存の SSJSVMの GCは他の処理系の GC

に比べて遅いことがわかった.そこで,GCの性能改善を狙って SSJSVMにマークスイー

プ GCを実装した.本研究で実装した GCの性能を調べるために,既存の SSJSVMと実行

時間を比較した.その結果,本研究の GCは SSJSVMの性能を改善しないことが分かった.

さらに調査した結果,本研究の GCはメモリ割り当てが遅いことがわかった.

キーワード JavaScript,ガベージコレクション,マークスイープ,BoehmGC

– i –

Page 3: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

Abstract

Design and Implementation of a Mark Sweep Garbage

Collection on a Server Side JavaScript Virtual Machine

Yuki TAKAMATSU

With the high functionality of Web browsers,Web applications widely spread.

Web applications are written in JavaScript and work on Web browsers.A Web appli-

cation communicates with a program running on the server to provide rich services to

the users.Recently,JavaScript spread as a language for server side programs of Web

applications.Therefore,studies of speeding up JavaScript processing on servers are

conducted flourishingly.On servers,it is expected that we often use large-scale pro-

grams.In this situation,it is garbage collection(GC)that greatly affect the execution

times of programs.GC is a routine that reclaims memory areas that are no longer used

so that the user program can reuse the areas.Because the execution of the program

stops during GC,GC affects the execution time of the program directly.In this study,

we investigated whether GC of a server side JavaScript virtual machine,SSJSVM,is

efficient compared to other JavaScript virtual machines.As a result,we found that GC

of SSJSVM was slower.Then,we implemented a mark sweep GC in SSJSVM aiming

the performance improvement.To investigate performance of the GC that we imple-

mented in this study,we compare the execution time of our SSJSVM with that of the

existing SSJSVM.As a result,we found that our GC did not improve performance.

Further investigation showed that memory allocation of our GC was mach slower than

that of the existing SSJSVM.

– ii –

Page 4: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

key words JavaScript,Garbage Collection,Mark Sweep,BoehmGC

– iii –

Page 5: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

目次

第 1章 はじめに 1

1.1 研究の背景 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.2 研究の目的 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.3 本研究の内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

第 2章 SSJSVM 4

2.1 SSJSVMとは . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.2 SSJSVMの構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.2.1 関数フレーム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2.2 関数テーブル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.2.3 JSValue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.2.4 グローバルオブジェクト . . . . . . . . . . . . . . . . . . . . . . . 9

2.2.5 オブジェクトの構造 . . . . . . . . . . . . . . . . . . . . . . . . . . 9

第 3章 SSJSVMのGC 13

3.1 GCの概要 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3.2 GCアルゴリズム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3.3 BoehmGC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3.4 SSJSVMにおける GCの検証 . . . . . . . . . . . . . . . . . . . . . . . . 16

3.4.1 検証方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.4.2 検証結果 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

第 4章 マークスイープGCの実装 20

4.1 マークスイープ GC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

4.1.1 マークフェーズ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

– iv –

Page 6: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

目次

4.1.2 スイープフェーズ . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

4.1.3 メモリ割り当て . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

4.2 設計 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

4.2.1 フリーリスト . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

4.2.2 GCのタイミング . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

4.2.3 マークフェーズ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

OBJECT型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

STRING型,FLONUM型 . . . . . . . . . . . . . . . . . . . . . . 26

ARRAY型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

その他の型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

4.2.4 スイープフェーズ . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

4.3 実装 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

4.3.1 GCの対象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

4.3.2 メモリの割り当て . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

4.3.3 マークの付与 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

4.3.4 オブジェクトの辿り方 . . . . . . . . . . . . . . . . . . . . . . . . . 33

JavaScriptのグローバル変数 . . . . . . . . . . . . . . . . . . . . . 33

JavaScriptのローカル変数 . . . . . . . . . . . . . . . . . . . . . . 33

C言語のグローバル変数 . . . . . . . . . . . . . . . . . . . . . . . 33

C言語のローカル変数 . . . . . . . . . . . . . . . . . . . . . . . . . 33

関数呼び出しの返り値を格納するレジスタ . . . . . . . . . . . . . . 34

汎用レジスタ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

文字列テーブル . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

第 5章 評価 36

5.1 検証方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

– v –

Page 7: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

目次

5.2 検証結果 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

5.3 考察 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

5.4 今後の課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

第 6章 関連研究 44

第 7章 おわりに 45

謝辞 46

参考文献 47

– vi –

Page 8: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

図目次

2.1 制御スタックの様子 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2 関数フレームの様子 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.3 STRING型と FLONUM型のオブジェクトの構造 . . . . . . . . . . . . . 11

2.4 STRING型と FLONUM型以外のオブジェクトの構造 . . . . . . . . . . . 12

2.5 オブジェクトのヘッダのフォーマット . . . . . . . . . . . . . . . . . . . . 12

2.6 グローバルオブジェクトとハッシュテーブル,配列の関係 . . . . . . . . . . 12

3.1 GCを持つシステムでのプログラムの実行 . . . . . . . . . . . . . . . . . . 14

3.2 quick処理系のメモリ割り当て . . . . . . . . . . . . . . . . . . . . . . . . 18

3.3 メモリを多く消費して頻繁に GCが起こるプログラムの実行時間の比較 . . 19

3.4 3種類の SSJSVM処理系と Node.jsの実行時間の比較 . . . . . . . . . . . 19

4.1 マークフェーズ時のヒープ領域 . . . . . . . . . . . . . . . . . . . . . . . . 21

4.2 スイープフェーズ時のヒープ領域 . . . . . . . . . . . . . . . . . . . . . . . 22

4.3 ヒープ領域上のフリーリストの様子 . . . . . . . . . . . . . . . . . . . . . . 23

4.4 OBJECT型オブジェクトの構造 . . . . . . . . . . . . . . . . . . . . . . . 25

4.5 STRING型,FLONUM型オブジェクトの構造 . . . . . . . . . . . . . . . 26

4.6 ARRAY型オブジェクトの構造 . . . . . . . . . . . . . . . . . . . . . . . . 27

4.7 スイープフェーズの動作の例 . . . . . . . . . . . . . . . . . . . . . . . . . 29

4.8 C言語のローカル変数を保存するスタック . . . . . . . . . . . . . . . . . . 34

5.1 オブジェクトの割り当てと malloc関数で使用したメモリ領域の大きさ . . . 38

5.2 オブジェクトの割り当てと malloc関数でのメモリ割り当ての回数 . . . . . 39

5.3 本研究の GCを持つ SSJSVMと既存の SSJSVMの実行時間の比較 . . . . 40

– vii –

Page 9: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

図目次

5.4 本研究の GC を持つ SSJSVM の実行時間の内訳と既存の SSJSVM の実行

時間の比較 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

5.5 オブジェクトが割り当てられる度にフリーリストを辿る回数 . . . . . . . . . 42

– viii –

Page 10: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

表目次

2.1 特殊レジスタ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2 オブジェクトのデータ型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

5.1 ヒープ領域の大きさに対する GCの回数 . . . . . . . . . . . . . . . . . . . 40

– ix –

Page 11: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

第 1章

はじめに

1.1 研究の背景

近年,サーバサイドでのWeb アプリケーションの開発言語として JavaScript が普及し

ている.Web アプリケーションとは,インターネットを通じて利用可能なソフトウェアで

ある.一般的なWebアプリケーションは,WebブラウザとWebサーバのプログラムが通

信を行って動作することで,一つのアプリケーションとなってWebブラウザ上で動作する.

このとき,ユーザが操作するWebブラウザ側をクライントサイド,Webサーバ側をサーバ

サイドと呼ぶ.今までは,主にクライアントサイドでは JavaScriptを使用し,サーバサイ

ドでは PHPなどのスクリプト言語を用いてアプリケーションの開発が行われてきた.しか

し,近年では以下のような理由により,サーバサイドでも JavaScriptが用いられるように

なってきた.まず JavaScript は,プロトタイプベースのオブジェクト指向言語であり,ク

ラスベースのオブジェクト指向言語とは違って,クラスに縛られずにオブジェクトを扱うこ

とができる.そのため,クラスベースほどプログラムが複雑化せず,単純な設計を行うこ

とができる.また,2000 年代中盤頃に Ajax と呼ばれる,JavaScriptによる非同期通信を

利用してクライアントサイドとサーバサイドで処理を分散させたり,動的にWebページの

内容を書き換えることができる技術の登場と共に飛躍的に進化を遂げてきた.これにより,

JavaScriptを扱えるプログラマが増え続けている.

次に,最近の JavaScript処理系のほとんどは Just In Time(JIT)コンパイルと呼ばれ

る高速化の機能が実装されている.これは,プログラムの実行時に,ソースコードや中間

コードなどを機械語にコンパイルすることで実行速度を高速化させるコンパイル手法であ

– 1 –

Page 12: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

1.1 研究の背景

る.JavaScriptはこのような高速化の研究が盛んであり,他のスクリプト言語に比べ高速化

の技術が蓄積されている.

このように,扱うことのできるプログラマが豊富であることと,高速な処理系が開発でき

ることからサーバサイドでも JavaScriptが注目されている.クライアントサイドと同じく

サーバサイドでも JavaScriptを使用することでプログラマが新たな言語を習得する必要が

無く,開発効率の向上が期待できる.そこでサーバサイド向け JavaScript仮想機械処理系

である SSJSVM(Server Side JavaScript Virtual Machine)[1]が開発された.

JavaScript仮想機械には通常,ガベージコレクション (以下,GC) と呼ばれる仕組みが

必要である [2].GCとは,プログラムが使わなくなったメモリ領域 (ごみ)を自動的に回収

する仕組みである.GCがあることで,プログラマは手動でメモリの管理をする必要が無く

なり,メモリを気にせずにプログラミングを行うことができるメリットがある.GCが無い

処理系では,利用可能なメモリ領域よりも多くのメモリ領域をプログラムが使用すると,実

行しているプログラムが途中で停止してしまう.そのため,SSJSVMでも GCが実装され

ている. 現在,SSJSVMの GCは,外部ライブラリである BoehmGC[3]を用いて実装さ

れている.BoehmGCとは C言語で開発された様々なソフトウェアで利用できるように作

られた汎用 GC ライブラリである.BoehmGC は様々なソフトウェアに対して安全に処理

を行うことができるように保守的 GCと呼ばれる手法で設計されている.保守的 GCとは,

対象のメモリ領域が回収対象なのかどうか曖昧な場合は,回収しないで安全に処理するとい

う手法である.そのため,様々な処理系に対して実装するのが簡単であるというメリットが

ある.その代わり,GCに使われるメモリ領域が多くなったり,使用可能な GCのアルゴリ

ズムが限定的で高速な GC アルゴリズムが適用できないため,GC の処理速度は遅い.ま

た,保守的 GCではプログラムが使っているデータには一切手を加えずに,どこがごみかを

判定したり,使われているメモリ領域どこかを憶えておく必要がある.そのために,管理用

のデータ構造を作り,プログラムにメモリを割り当てたり GCするときに,管理用のデータ

構造もあわせて操作する必要がある.したがって,保守的 GCのオーバーヘッドのために,

SSJSVMに特化した GCを作成した場合に比べて性能が劣ると考えられる.

– 2 –

Page 13: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

1.2 研究の目的

1.2 研究の目的

サーバサイドで大規模なプログラムを動かす際に,プログラムの処理時間に大きく影響を

与えるのが GC にかかる時間である.そのため,GC に時間がかかる処理系は望ましくな

い.そこで,本研究では,サーバサイド向け JavaScript仮想機械である SSJSVMのGCを

高速化する.

1.3 本研究の内容

本研究では,まず SSJSVM の構造を調査の調査を行う.SSJSVM がどのような処理系

なのか,どのような仕組みで動作しているのかを調べて SSJSVMのプログラムを理解する

(2 章).さらに,SSJSVM の性能を調査した.また,他のサーバサイド JavaScript 処理

系と処理速度を比較する.その結果から,SSJSVMに専用の GCを実装することで高速化

の余地があることがわかった(3章).そこで,SSJSVMに専用の GCを設計し実装した.

SSJSVMの構造にしたがって適したマークスイープ GCの設計をした.設計にしたがって,

SSJSVMにマークスイープ GCを実装した(4章).SSJSVMに実装したマークスイープ

GCについて,SSJSVMと比較を行い,性能を検証した.この検証から,本研究のマークス

イープ GCは遅いことがわかった.原因は,メモリ割り当てが遅いことである(5章).

– 3 –

Page 14: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

第 2章

SSJSVM

第 2 章では,SSJSVM がどのような構成で作られている処理系なのかを説明する.

SSJSVMで JavaScriptのプログラムをどのように実行するかを説明し,実行時に関わる処

理や SSJSVMの構造について説明する.本研究では SSJSVMに適した GCを実装するた

め,SSJSVMの構造を理解する必要がある.

2.1 SSJSVMとは

SSJSVMは中間コードにコンパイルした JavaScriptのプログラムの解釈実行を行うレジ

スタベースの仮想機械である.SSJSVMで JavaScriptのプログラムを実行するには,まず

SSJSコンパイラを用いてコンパイルし,JavaScriptのプログラムを SSJSVMで実行する

ための中間コードであるバイトコードに変換し,そのバイトコードを SSJSVMによって実

行する.JavaScriptの簡単なソースコードの例をソースコード 2.1に示す.このコードは変

数宣言と整数の加算を行っているコードである.このコードを SSJSVMコンパイラでコン

パイルして出力されるバイトコードをソースコード 2.2に示す.このバイトコードは,1行

に 1つの命令を持つ,各命令は最大 3つの引数をとる.例えば,14行目の命令の意味は,8

番レジスタの値と 9 番レジスタの値を足したものを 2 番レジスタに格納するという処理で

ある.

SSJSVM は高速な処理系を目指して開発しており,サーバサイドで動作することを前提

としている.また,SSJSVM は C 言語で開発されている.そのため,現在は SSJSVMの

GCには C言語に対応した汎用 GCライブラリである BoehmGCが利用されている [4].

– 4 –

Page 15: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

2.2 SSJSVMの構成

ソースコード 2.1 JavaScriptのソースコードの例

1: var a;

2: var b = 10;

3: a = b + 1;

ソースコード 2.2 JavaScriptのバイトコードの例

1: funcLength 1

2: callentry 0

3: sendentry 0

4: numberOfLocals 0

5: numberOfInstruction 13

6: getglobalobj 1

7: setfl 15

8: fixnum 2 10

9: string 5 ”b”

10: setglobal 5 2

11: string 10 ”b”

12: getglobal 8 10

13: fixnum 9 1

14: add 2 8 9

15: string 11 ”a”

16: setglobal 11 2

17: seta 2

18: ret

2.2 SSJSVMの構成

SSJSVM はレジスタ操作でバイトコードを実行する仮想機械である.実行時は,

JavaScriptのプログラムの関数ごとに処理を行っている.関数を汎用レジスタの集合を使っ

て実行する.各関数で使う汎用レジスタを図 2.1のように制御スタックに積んで,関数ごと

– 5 –

Page 16: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

2.2 SSJSVMの構成

に処理を行う構造になっている.説明のために例として関数内で関数を呼び出す JavaScript

のプログラムをソースコード 2.3で示す.このソースコードは関数 fの中で関数 gを呼び出

しているプログラムである.以降の SSJSVM内の構成に関する説明は全て,ソースコード

2.3 のプログラムを実行する時の SSJSVM の動作に基づいて説明を行う.図 2.1 では,関

数内で関数呼び出しを行った際の制御スタックの様子を示している.関数 fが最初に呼び出

されているので,制御スタックには関数 fに関する汎用レジスタ群が積まれる.さらに,関

数 fの中で関数 gを呼び出しているので,制御スタックの関数 fの汎用レジスタ群の上に

関数 gの汎用レジスタ群が積まれる.ただし,関数呼び出しを行っているので,呼び出し元

の関数に戻るために,呼び出し先の汎用レジスタ群が積まれる前に,現在の関数の戻り番地

等の情報を制御スタックに記録しておく.

制御スタックを操作して関数を実行するために,現在実行している関数の実行情報を保持

しておく必要がある.そこで,現在実行している関数に関しては,特殊レジスタが用意され

ており,そこで現在実行している関数の実行情報を保持している.特殊レジスタの概要を表

2.1に示す.特殊レジスタに格納された値は,制御スタック上の実行中の関数の場所を示す

ものや,関数フレームの参照,関数の返り値など関数の実行に必要な情報が格納されている.

ソースコード 2.3 関数内で関数を呼び出す JavaScriptのソースコードの例

1: var n = 2;

2: var g = function(t){

3: var m = t + 1;

4: return m;

5: }

6: var f = function(s) {

7: return g(s + 1)

8: }

9: f(n);

– 6 –

Page 17: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

2.2 SSJSVMの構成

図 2.1 制御スタックの様子

表 2.1 特殊レジスタ

レジスタ名 レジスタが示すもの

fp 実行中の関数のレジスタ群の開始位置を示す.

sp 実行中の関数のレジスタ群の終点位置を示す.

lp 実行中の関数の関数フレームの参照を示す.

cf 関数テーブル内の実行中の関数が保持している命令列の参照を示す.

pc 実行中のプログラムカウンタを示す.

a 関数の返り値を示す.

2.2.1 関数フレーム

SSJSVMでは関数を呼び出す度に関数フレームが作成される.関数フレームは関数の引

数を格納するオブジェクトや,ローカル変数,関数が宣言された関数フレームに対する参照,

及び関数内で定義されたローカル変数のオブジェクトなどで構成される.関数フレームの例

を図 2.2に示す.図 2.2の prev frameは関数が宣言された場所の関数フレームを指す参照

である.また,auguments は関数の引数を示しており,残りは関数内のローカル変数を格

納している.

– 7 –

Page 18: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

2.2 SSJSVMの構成

図 2.2 関数フレームの様子

2.2.2 関数テーブル

JavaScript プログラム中の全ての関数はプログラム中で宣言された順に関数テーブルに

格納される.関数テーブル内のそれぞれの関数は,その関数に対応するバイトコードの命令

列を保持している.

2.2.3 JSValue

レジスタに格納する値は 64bitのワードであり,真偽値や整数値はデータそのものを表し,

オブジェクトや関数はデータを格納している場所を示す.データには,整数や真偽値,オブ

ジェクトや関数など様々な型がある.そこで,データを示す 64bitのワードの中で,それぞ

れのデータの型とデータを示す場所を表している.データを指すアドレスは必ず 8 の倍数

となっているため,下位 3bitは全て 0である.そのため,データの型を下位 3bitに埋め込

んで表し,それ以外でデータを指すアドレスを表している.下位 3bitでデータの型を表す

– 8 –

Page 19: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

2.2 SSJSVMの構成

ため,それぞれのデータの型には 3bitで表現できるタグ値が対応付けられている.例えば,

整数 (タグ値 7)は上位 61bitで符号付き 61bit整数を表現して扱い,オブジェクトや関数な

どはヒープ領域上の割り当てられた領域を指すポインタにタグ値が組み込まれて表現され

る.このような,データを指す 64bitのワードを SSJSVMでは JSValueとして定義してい

る.SSJSVMのプログラム中では JSValue型の変数などにデータの参照が格納されている.

2.2.4 グローバルオブジェクト

JavaScript プログラムの関数内のローカル変数など,関数に関するデータは関数フレー

ムに保持されているのに対して,関数外のデータであるグローバル変数などは,グローバ

ルオブジェクトと呼ばれる専用のオブジェクトのプロパティに保持される.SSJSVM には

JavaScript のプログラムのグローバル環境でのデータを保存しておくために,グローバル

オブジェクトと呼ばれるオブジェクトが存在する.グローバルオブジェクトのプロパティに

は JavaScriptプログラムのグローバル変数が宣言された順に格納されている.

グローバルオブジェクトや特殊レジスタなど,JavaScriptのプログラムを実行するのに必

要な内部情報をまとめたものを実行コンテキストと呼び,SSJSVMではコンテキスト構造

体として用意されている.グローバルオブジェクトはこのコンテキスト構造体から参照され

ている.

2.2.5 オブジェクトの構造

オブジェクトにも様々なデータ型がある.オブジェクトのデータ型は,全部で 11種類存

在する.オブジェクトの全てのデータ型にはタグ値が対応付けされており,オブジェクトの

データ型とタグ値の対応付けを表 2.2に示す.

全てのオブジェクトはヘッダとデータを保持するプロパティを持っている.データ型に

よって保持するプロパティが異なるため,オブジェクトの構造はそれぞれのデータ型によっ

て異なっている.しかし,共通して全てのオブジェクトは必ずヘッダを保持している.オブ

– 9 –

Page 20: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

2.2 SSJSVMの構成

表 2.2 オブジェクトのデータ型

データ型 型の説明 タグ値 (16進数)

STRING 文字列型 4

FLONUM 浮動小数点型 5

OBJECT 一般オブジェクト型 6

ARRAY 配列型 7

FUNCTION 関数型 8

BUILTIN 組み込み関数型 9

ITERATOR イテレータ型 a

REGEXP 正規表現型 b

STRINGOBJECT 文字列参照型 c

NUMBEROBJECT 数値参照型 d

BOOLEANOBJECT 真偽値参照型 e

ジェクトのヘッダの大きさは 64bitであり,上位 32bitでオブジェクトのサイズ,下位 3bit

でオブジェクトのデータ型を表している.このときの,オブジェクトのヘッダ部分のフォー

マットを図 2.5に示す.

データ型は大きく 2つに分けて考えることができる.STRING型,FLONUM型のデー

タ型とそれ以外の全てのデータ型である.STRING型と FLONUM型では文字列や浮動小

数点をそのままオブジェクトのプロパティとして保持しているオブジェクトである.それ以

外のデータ型は全て OBJECT型と同じプロパティを保持しており,それに加えそれぞれの

データ型で必要なプロパティを保持している.STRING型,FLONUM型のオブジェクト

の構造を図 2.3に,それ以外のオブジェクトの構造を図 2.4に示す.図 2.3は STRING型と

FLONUM 型の構造を示しており,ヘッダと値を保持することができる構造になっている.

また,図 2.4は STRING型と FLONUM型以外のデータ型の構造を示しており,OBJECT

– 10 –

Page 21: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

2.2 SSJSVMの構成

型のプロパティとそれぞれのデータ型のプロパティを保持することができる構造になって

いる.

STRING型と FLONUM型のオブジェクトはそのままプロパティにアクセスすることで

必要なデータを得ることができる.それ以外の型のオブジェクトは,配列でデータを格納し

ており,その配列にアクセスするためにはハッシュテーブルから必要なデータが格納されて

いる場所を探してアクセスする.例としてグローバルオブジェクトにグローバル変数の値

が格納されている時のオブジェクトの様子を示す.このときの,グローバルオブジェクト,

ハッシュテーブル,配列の関係を図 2.6に示す.図では,mapから指されたハッシュテーブ

ル上でグローバル変数 aとグローバル変数 aの値が格納されている prop配列の場所が対応

付けられている.また,グローバルオブジェクトは numberOfProp,limitOfProp という

2つのプロパティを保持している.numberOfPropは prop配列の使われている長さを示し

ており,limitOfPropは prop配列の長さの限界を示している [5].

図 2.3 STRING型と FLONUM型のオブジェクトの構造

– 11 –

Page 22: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

2.2 SSJSVMの構成

図 2.4 STRING型と FLONUM型以外のオブジェクトの構造

図 2.5 オブジェクトのヘッダのフォーマット

図 2.6 グローバルオブジェクトとハッシュテーブル,配列の関係

– 12 –

Page 23: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

第 3章

SSJSVM の GC

第 3章では,SSJSVMに GCを実装する前に GCがどのような機能を持ったプログラム

なのかを説明する.また,既存の SSJSVMに実装されている BoehmGCがどのような GC

なのかを説明する.その上で,既存の SSJSVMの GCの性能を調査して,SSJSVMに専用

の GCを実装することで性能改善できるかを調べる.

3.1 GCの概要

GC とは,プログラムが使わなくなったメモリ領域 (ごみ) を自動的に回収して再利用可

能にする仕組みである.GCの動作は,まずメモリ領域上のごみを発見して,見つけたごみ

を回収する.そしてプログラムが再度利用できるようにし,再びプログラムからの要求に応

じてメモリを割り当てる.これらの機能を持ったプログラムが GCである.

通常 GCはを持つシステムでは,プログラムの開始時にシステムが必要なメモリ領域を予

め確保しておき,実行中には確保した領域内にデータを配置する.このとき,メモリ領域上

に予め確保しておく領域をヒープ領域と呼ぶ.また,GCによって操作されるこれらのデー

タをオブジェクトと呼ぶ.ヒープ領域に配置されたオブジェクトは GCで操作するため,配

置するオブジェクトにはオブジェクト自体の情報を持たせる必要がある.そのため,オブ

ジェクトにはヘッダを付与して,オブジェクトの情報を保持する.ヘッダに付与される情報

は,主にオブジェクトのサイズやオブジェクトの種類である.また,オブジェクトはプログ

ラムを実行する際に必要なデータを保持している.これらを保持している場所をフィールド

と呼び,プログラムは必要に応じてオブジェクトのフィールドにアクセスしてデータを参照

– 13 –

Page 24: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

3.1 GCの概要

したり書き換えたりする.プログラムは一般的に,オブジェクトを参照で連結したデータ構

造を作り,その参照がポインタで実現されている.そのため,GCはそれを利用してポイン

タを辿り,オブジェクトからさらに別のオブジェクトを探索する.整数などのポインタでは

ないものを非ポインタと呼ぶことにする.非ポインタに対しては GCは何も操作しない.

ヒープ領域に割り当てられたオブジェクトのうち,プログラムから参照できて,GC以降

もプログラム中で使われる可能性のあるオブジェクトを生きているオブジェクト,プログラ

ムからはどうやっても参照できないオブジェクトを死んでいるオブジェクトと呼ぶ.プログ

ラムからどうやっても参照できないため,死んでいるオブジェクトはごみと呼ばれている.

プログラムからの参照の有無でオブジェクトが生きているか死んでいるかを判断するた

め,GCはプログラムからの参照の有無を判断する必要がある.プログラムが持つ参照の元

となる部分をルートと呼ぶ.例えば,グローバル変数が指す先はプログラムから参照可能な

ため,グローバル変数はルートとなる.

プログラムの実行中に GC が起こるとプログラムは処理を停止して GC を実行する.そ

のため,図 3.1のようにプログラムの実行ではプログラムの本来の処理の合間にメモリの割

り当てとごみの回収を行っていることになる [6].

図 3.1 GCを持つシステムでのプログラムの実行

– 14 –

Page 25: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

3.2 GCアルゴリズム

3.2 GCアルゴリズム

GCは,様々なアルゴリズムのもと作られている.様々なアルゴリズムが存在するが,中

心となっているアルゴリズムは,以下の 3つのアルゴリズムである.他のアルゴリズムはこ

の 3つのアルゴリズムを組み合わせたり,応用してできたアルゴリズムしか存在しない.

• マークスイープ GC

• 参照カウント

• コピー GC

GCアルゴリズムは,それぞれのアルゴリズムによって特徴が異なっており,様々なメリッ

トやデメリットを持つ.例えば,マークスイープ GCは,実装が簡単でヒープ領域の使用効

率が良いがメモリ割り当てが遅く,参照カウントは GCが発生してプログラムが停止してい

る時間が短いが実装が複雑でヒープ領域の使用効率が悪い.また,コピー GCは GC1回に

かかる時間は比較的短いがヒープ領域の使用効率が悪い GC アルゴリズムである.このよ

うにアルゴリズムによって特徴が異なるため,GCアルゴリズムはプログラムに適したもの

を選択する必要がある.本研究では,比較的実装が簡単なため,マークスイープ GCを実装

する.

3.3 BoehmGC

SSJSVM は,C 言語用の GC ライブラリである BoehmGC を使って GC を実装してい

る.BoehmGCは保守的 GCという手法で設計されている.保守的 GCとは,ルートから

オブジェクトを指している値が,ポインタであっても,ポインタでは無いポインタに似た整

数値であっても,生きているオブジェクトとみなす手法で設計された GC である.通常の

GCはオブジェクトをポインタで辿って探すため,非ポインタに対しては何もしない.しか

し例えば,たまたまヒープ領域上のオブジェクトのアドレスと同じ整数値が辿っているルー

トやオブジェクトのフィールド中に存在した場合に,GCはそれを非ポインタであるかポイ

– 15 –

Page 26: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

3.4 SSJSVMにおける GCの検証

ンタであるかを判別することができない.この場合に,ポインタのように見える非ポインタ

が指すオブジェクトも生きているオブジェクトとみなす.このように,ポインタの可能性の

ある値はすべてポインタとみなすので安全に処理を行うことができる.

保守的 GCはポインタを正確に判別することができないため,ヒープ領域上のオブジェク

トを移動させる処理をする GCアルゴリズムは利用できない.例えば,オブジェクトを移動

させる場合は移動前のオブジェクトを指しているポインタを移動先のオブジェクトに指し変

えなければならない.しかし,ポインタと非ポインタを判別することができない保守的 GC

がポインタの値を書き換えると,非ポインタの値を書き換えてしまう恐れがある.そのた

め,保守的 GCはオブジェクトの移動ができない.そこで BoehmGCではオブジェクトを

移動する処理の無い GCアルゴリズムである,マークスイープ GCが用いられている.

保守的 GCのメリットとしては,プログラムが GCに依存しないため,GCの実装が楽で

あるという点である.そのため,様々なソフトウェアに対して安全に処理を行うことができ

る.しかし,上述したように保守的 GC ではオブジェクトを移動させる処理のある GC ア

ルゴリズムが使えないため,利用できる GC アルゴリズムが限定的になる.そのため,高

速な GCアルゴリズムを適用することができないので,BoehmGCは遅いと考える.特に,

メモリを多く使う処理を行う場合に,専用の GCを備えた他のサーバサイド JavaScript処

理系に比べて SSJSVMは処理速度が遅くなると考えられる.そこで本研究では,SSJSVM

が本当に遅いかどうか検証する.

3.4 SSJSVMにおけるGCの検証

3.4.1 検証方法

SSJSVMは保守的 GCを利用しているため,GCが遅いと考えられる.なので,本当に

遅いのか検証を行って確かめる.検証では,GCにかかっている時間とメモリ割り当てにか

かる時間を調べたいので,以下の 3種類の SSJSVM処理系を用いてプログラムの実行時間

を比較する.

– 16 –

Page 27: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

3.4 SSJSVMにおける GCの検証

• BoehmGCを利用した通常の SSJSVM(BoehmGC処理系)

• ごみ回収を行わない mallocによるメモリ割り当てを行う SSJSVM(malloc処理系)

• ごみ回収を行わないが高速なメモリ割り当てを実装した SSJSVM(quick処理系)

malloc処理系は,メモリが必要になる度に C言語の標準ライブラリ関数である malloc関

数を用いてメモリの割り当てを行う.ただし,ごみの回収を行わないため利用可能なメモ

リ領域以上のメモリ領域を割り当てるプログラムは動作しない.quick 処理系は,最初に

malloc 関数で 2GB 分のメモリ領域を確保し,確保したメモリを端から順に利用すること

で高速なメモリ割り当てを行う処理系である.図 3.2では,確保した 2GBのメモリ領域を

プログラムからの要求にしたがって,メモリ領域の端から順にメモリを割り当てている様

子を示している.malloc処理系ではメモリが必要になる度に毎回 malloc関数の呼び出し

によるメモリの確保を行っていたが,quick処理系では malloc関数の呼び出しによるメモ

リの確保を一回しか行わないため,メモリの確保にかかる時間が大幅に減ると考えられる.

quick処理系もmalloc処理系と同じくごみの回収は行わない.これらの処理系を用いて,

GCが頻繁に起こるようにごみを大量に生成するプログラムを実行する.

BoehmGC 処理系と malloc 処理系はメモリ割り当ての方式が近いため,この 2 つの

処理系を比較することでごみ回収にかかった時間が推定できる.また,malloc 処理系と

quick処理系はどちらもごみの回収は行わないが,メモリ割り当ての方式が異なるため,こ

の 2つの処理系を比較することでメモリ割り当てにかかる時間が推定できる.

検証に用いたプログラムは,GCを頻繁に起こさせるために死んでいるオブジェクトを多

数生成するプログラムである.このプログラムを 3つの処理系で実行して比較した.また,

検証を行った環境は,Ubuntu14.04,Intel Core i5 3.3GHZ,gcc 4.8.4である.

3.4.2 検証結果

検証結果のグラフを図 3.3 に示す.このグラフは縦軸をプログラムの実行時間,横軸を

生成したごみの数としており,3種類の処理系の実行時間を表したグラフである.このグラ

– 17 –

Page 28: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

3.4 SSJSVMにおける GCの検証

図 3.2 quick処理系のメモリ割り当て

フのmalloc処理系と quick処理系は共にごみ回収を行わずに,メモリ割り当ての方法が

違うことから,実行時間の差はメモリの割り当てにかかった時間であることがわかる.ま

た,BoehmGC 処理系と malloc 処理系は,ごみの回収を行っているか行っていないか

の違いなので,実行時間の差からごみ回収にかかった時間がわかる.これらの結果から,

BoehmGC はメモリの割り当てにかかった時間もごみの回収にかかった時間も遅いので,

BoehmGCは処理が遅いということがわかる.

また,一般的なサーバサイド JavaScriptとの差を比べるために,V8 JavaScriptエンジン

で動作するサーバサイド JavaScriptである Node.jsとの比較を行った.その結果のグラフ

を図 3.4に示す.このグラフは縦軸をプログラムの実行時間,横軸を生成したごみの数とし

ており,図 3.3のグラフに Node.jsでの実行結果を加えたものである.グラフより,Node.js

は GCを含んでいるにもかかわらず高速に処理をしているということがわかる.この結果か

ら,Node.jsの GCに比べて BoehmGCは遅いということがわかった.

以上の検証により,BoehmGCはごみ回収もメモリの割り当ても遅いということがわかっ

た.また,専用の GCを持つ Node.jsは BoehmGCに比べて速いということがわかったた

め,SSJSVM専用の GCを実装することで高速化の余地があることがわかった.

– 18 –

Page 29: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

3.4 SSJSVMにおける GCの検証

図 3.3 メモリを多く消費して頻繁に GCが起こるプログラムの実行時間の比較

図 3.4 3種類の SSJSVM処理系と Node.jsの実行時間の比較

– 19 –

Page 30: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

第 4章

マークスイープ GC の実装

第 3章では,BoehmGCが使われている既存の SSJSVMの GCの性能を調査した.その

結果 BoehmGCは遅いことがわかった.BoehmGCは保守的 GCであるため,ヒープ領域

上のオブジェクトを移動させるような処理はできない.そのため,高速な GC アルゴリズ

ムを適用させることができず処理が遅い.そこで本研究では,SSJSVMに保守的では無い

マークスイープ GCを実装する.マークスイープ GCを選んだ理由は,GCアルゴリズムの

中でも比較的実装が簡単であることである.

4.1 マークスイープGC

マークスイープ GC とはマークフェーズとスイープフェーズの 2 つのステップから成る

GCアルゴリズムである.マークフェーズではヒープ領域上の全ての生きているオブジェク

トに生きていることを示すマークをつける.スイープフェーズは,ヒープ領域上のマークの

ついていないオブジェクトを全て回収する.回収したメモリ領域は,フリーリストと呼ばれ

る空き領域のリストに繋げられる.プログラムからメモリが要求される度に,フリーリスト

からメモリを割り当てる.以下で詳しく説明する.

4.1.1 マークフェーズ

マークフェーズでは,まず最初にアプリケーションから直接参照されているヒープ領域上

のオブジェクトのヘッダにマークをつける.このマークをつけたオブジェクトは生きている

オブジェクトであり,ここから辿れる全てのオブジェクトにも再帰的にマークをつけていく.

– 20 –

Page 31: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.1 マークスイープ GC

図 4.1 マークフェーズ時のヒープ領域

こうすることで,メモリ領域上の全ての生きているオブジェクトにマークをつけることが可

能となる.再帰的に全てのオブジェクトを辿る際に,マーク済みのオブジェクトに辿り着い

た場合には,そこから先のオブジェクトは辿らないようにすることで繰り返し辿らないよう

にする.

マークフェーズ時におけるメモリ領域の状態を図 4.1に示す.この図は,プログラムから

参照されるヒープ領域上に割り当てられたオブジェクトのヘッダにマークをつけている様子

を表している.プログラムから直接参照されるオブジェクトだけではなく,オブジェクトか

ら参照されているオブジェクトにもマークしており,プログラムから辿れる全てのオブジェ

クトにマークをつけている.

4.1.2 スイープフェーズ

スイープフェーズでは,まず最初にヒープ領域の一番端のオブジェクトから順に全てのオ

ブジェクトのヘッダをスキャンしていく.そして,ヘッダにマークの付いていないオブジェ

クトを発見すると,回収して再利用可能な空き領域にする.オブジェクトのヘッダにマーク

が付いている場合は,マークを外して次の GCに備える.回収されてできたヒープ領域上の

空き領域は,フリーリストに繋いで確保しておくことで,プログラムからのメモリ要求に備

– 21 –

Page 32: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.2 設計

図 4.2 スイープフェーズ時のヒープ領域

える.

スイープフェーズ時におけるメモリ領域の状態を図 4.2に示す.この図は,図 4.1のマー

クフェーズ時にマークを付けなかったヒープ領域上のオブジェクトを全て回収し,再度利用

可能にするためにフリーリストに繋いだ図である.

4.1.3 メモリ割り当て

プログラムからのメモリの要求に応じるために,ヒープ領域上の空き領域を繋げて確保し

ているリストをフリーリストと呼ぶ.プログラムからメモリの要求があれば,フリーリスト

の先頭から順に必要なサイズ以上の空き領域を探して,空き領域が見つかればその空き領域

をプログラムに渡す.この時,必要なサイズ以上の空き領域が見つからなかった場合は GC

を発生させて,新たな空き領域をフリーリストに確保する.それでも見つからない場合はプ

ログラムは停止する.

4.2 設計

本研究にて実装するマークスイープ GCの概要を説明する.マークスイープ GC に必要

なフリーリストの構造や,GCが発生するタイミング,マークフェーズとスイープフェーズ

– 22 –

Page 33: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.2 設計

におけるプログラムの動作について示す.

4.2.1 フリーリスト

ヒープ領域上の空き領域には,空き領域のサイズとフリーリストの次の空き領域の先頭ア

ドレスを記憶させておくヘッダを付与する.ヘッダはオブジェクトのヘッダと同じ構造にし

ておく,ヘッダを付与するのは,スイープフェーズの処理で空き領域を見分けられるように

するためである.このときのフリーリストを図 4.3に示す.図は,ヒープ領域上の空き領域

にヘッダを付与し,ヘッダは空き領域のサイズと次の空き領域を指すアドレスを持つことを

表している.

プログラムからメモリの要求があった場合はフリーリストの先頭の空き領域から順にリ

ストを辿り,要求されたサイズ以上のサイズの空き領域を探す.空き領域が見つかれば,そ

こから必要な大きさの領域を切り取ってオブジェクトを割り当てる.切り取られて余った領

域は再びフリーリストに繋ぐことでヒープ領域の節約をする.ただし,先程も述べたよう

にフリーリストにはヘッダを付与するので,空き領域をフリーリストに繋ぐためには,最低

16Byteの領域が必要である.そのため,切り取られて余った領域が 16Byteに満たない場

合は,その領域にはオブジェクトを割り当てない.ゆえに,プログラムからの要求で空き領

域を割り当てる条件は,要求されたサイズより空き領域が 16Byte以上大きい場合か,要求

されたサイズと全く同じサイズの空き領域であることである.

図 4.3 ヒープ領域上のフリーリストの様子

– 23 –

Page 34: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.2 設計

4.2.2 GCのタイミング

本研究では,オブジェクトの作成に必要なメモリの割り当ては全てフリーリストから探し

て割り当てている.フリーリストに要求されたメモリサイズ以上の空き領域が存在しなかっ

た時に GCを行う.

4.2.3 マークフェーズ

本研究で扱うオブジェクトは,64bitのヘッダを保持している.オブジェクトのヘッダの

64bitのうち上位 32bitでオブジェクトのサイズ,下位 3bitでオブジェクトの型を表してい

る.しかし,現在ではヘッダの 64bit中 4bit目から 32bit目までは利用されていない.そこ

で,本研究ではヘッダの下から 5bit目をマークビットとし,この bitが 0なのか 1なのか

を見て判断する.マークビットが 0であればマークされていない死んでいるオブジェクトで

あり,1であればマークされている生きているオブジェクトである.

マークフェーズでは,ルートから指されているオブジェクトと,そこから辿れる全てのオ

ブジェクトに再帰的にマークをしていく.生きているオブジェクトを発見したら,そのオブ

ジェクトのヘッダに生きている証のマークを付けるする.SSJSVM において,ルートとな

る場所を以下に示す.

• JavaScriptのグローバル変数

• JavaScriptのローカル変数

• C言語のグローバル変数

• C言語のローカル変数

• 関数呼び出しの返り値を格納するレジスタ

• 汎用レジスタ

• 文字列テーブル

ルートから指されたオブジェクトが見つかったら,そこから再帰的にオブジェクトを辿ら

– 24 –

Page 35: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.2 設計

なければならない.しかし,オブジェクトのデータ型によって,オブジェクトから辿る先が

異なってくる.そこで,以下では第 2 章の表 2.2 で示したデータ型のそれぞれの辿り方を

示す.

OBJECT型

OBJECT型のオブジェクトは,ヘッダ以外に 4つのプロパティを保持している.それは,

配列にどこまでデータが格納されているかを表す値,配列の限界の長さの値,ハッシュテー

ブル,データを格納する配列の 4種類である.このうちオブジェクトから辿る必要のあるプ

ロパティはデータを格納する配列である.そして,配列に格納されているデータから指され

ているオブジェクトを辿る.図 4.4は OBJECT型オブジェクトの構造を示しており,prop

プロパティで指された配列を探索する.この図では,headerがヘッダ,numberOfPropが

配列にどこまでデータが格納されているかを表す値,limitOfProp が配列の限界の長さ,

mapがハッシュテーブルを示している.

図 4.4 OBJECT型オブジェクトの構造

– 25 –

Page 36: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.2 設計

図 4.5 STRING型,FLONUM型オブジェクトの構造

STRING型,FLONUM型

STRING型と FLONUM型の 2つのオブジェクトは,それぞれ文字列と浮動小数点を保

持するだけのオブジェクトであるため,このオブジェクトから先に辿るオブジェクトは存在

しない.そのため,この 2つの型のオブジェクトが見つかった場合はそこから先は辿らない.

図 4.5は STRING型,FLONUM型オブジェクトの構造を示している.図のように,ヘッ

ダと値を保存するプロパティの 2つのプロパティで構成されているため,これ以上辿る配列

は存在しない.

ARRAY型

ARRAY型のオブジェクトは,他のデータ型のオブジェクトと違って,OBJECT型と共

通のプロパティの配列以外にも辿らなければならないフィールドがある.ARRAY 型のオ

ブジェクトは配列を扱う構造体であるため,配列の中身も辿らなければならない.プログ

ラムから指されている ARRAY型オブジェクトの構造を図 4.6に示す.ARRAY型のオブ

ジェクトは OBJECT型同様に propプロパティで指された配列の以外にも,ARRAY型オ

ブジェクトが表している配列本体である bodyプロパティで指された配列も探索する必要が

ある.

– 26 –

Page 37: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.2 設計

図 4.6 ARRAY型オブジェクトの構造

その他の型

上記に上げた OBJECT型,STRING型,FLONUM型,ARRAY型の 4つオブジェク

ト以外のデータ型のオブジェクトについては,オブジェクトの辿り方は OBJECT型と同じ

である.なぜなら 4つのオブジェクト以外のデータ型は全て OBJECT型と同じデータ構造

を持っているため,その OBJECT型のデータ構造から他のオブジェクトを辿れるためであ

る.そのため,この 4つの型以外の型は全て OBJECT型と同じ辿り方で再帰的にオブジェ

クトを辿ることができる.

4.2.4 スイープフェーズ

本研究では,ヒープ領域上にあるオブジェクトとフリーリストに繋がれた空き領域は共に

それぞれの領域のサイズを記憶しているヘッダを持っている.そのため,ヒープ領域の先頭

から,ヘッダに記憶されている領域サイズずつ移動することで全てのオブジェクトまたは空

き領域へアクセスすることができる.

スイープフェーズで行う動作を以下に示す.まず,ヒープ領域の一番端のオブジェクトか

– 27 –

Page 38: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.3 実装

らヘッダに記述されたサイズごとにヒープ領域を移動して全てのオブジェクトまたは空き領

域を順に辿る.このとき,オブジェクトのヘッダのマークビットが 1になっていれば,その

オブジェクトは生きているため,そのオブジェクトのマークビットを 0にして次のオブジェ

クトへ移る.オブジェクトのビットマークが 0の場合,もしくは元々フリーリストに繋がれ

ていた空き領域の場合 (ヘッダのマークビットは 0)は,どちらも空き領域なのでフリーリス

トのヘッダを付与してフリーリストに繋ぐ.ただし,マークビットが 0のオブジェクトまた

は空き領域が連続して続く場合は,連続して続いている領域を合計して記憶しておき,次に

マークビットが 1のオブジェクトが現れたときに,合計した領域にフリーリストのヘッダを

付与してフリーリストに繋ぐ.このようにヒープ領域をスキャンする中で,生きているオブ

ジェクトどうしの間の領域をフリーリストに繋いでいくことで死んでいるオブジェクトを回

収する.

動作の例を図 4.7で示す.この図では,スイープフェーズ前の死んでいるオブジェクトと

フリーリストに繋がれた空き領域が,スイープフェーズ後には全てフリーリストに繋がれて

いる.また,死んでいるオブジェクトとフリーリストに繋がれた空き領域が連続していた領

域は,スイープフェーズ後にはまとめて大きなサイズの空き領域としてフリーリストに繋が

れている.

本研究ではスイープフェーズに入る度に新たに 1からフリーリストを作りなおすことでフ

リーリストを作成する.こうすることで,GCが進む度にフリーリストが細分化されてしま

う問題を解決しながら,フリーリストを作成することができる.

4.3 実装

4.3.1 GCの対象

本研究では,GC によってごみ回収を行う対象を,SSJSVM 内で多数生成される 11 種

類のデータ型を持つオブジェクトとする.SSJSVM内では C言語の標準ライブラリである

malloc関数を用いて至る所でメモリの割り当てを行っている.そのため,malloc関数を用

– 28 –

Page 39: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.3 実装

図 4.7 スイープフェーズの動作の例

いて割り当てたメモリ領域は GCの対象になるが,今回は時間の都合でオブジェクトのみを

GCの対象にする.例えば,オブジェクトは必要なデータをオブジェクトの持つ配列に格納

して保存しており,その配列にアクセスするためにハッシュテーブルを用いて必要なデータ

が格納されている場所を探してアクセスする.そのため,オブジェクトにはハッシュテーブ

ルが必要なので,オブジェクトが作られる度にハッシュテーブルも malloc関数を用いて作

成される.しかし,今回はオブジェクトは GCの対象とするが,ハッシュテーブルについて

は GCの対象外としている.

4.3.2 メモリの割り当て

本研究では,最初のオブジェクトが作成される前に,一度だけ任意のサイズのヒープ領域

を確保し,その確保したヒープ領域上にオブジェクトを配置していくことでメモリをオブ

ジェクトに割り当てる.今回実装した GCでは,プログラマが自由にヒープ領域のサイズを

決めることができるようになっている.最初にヒープ領域を確保する際は,確保した領域が

フリーリストに繋げられて空き領域となる.

– 29 –

Page 40: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.3 実装

プログラムからの要求がある度に,フリーリストを端から順に探索していくので,常にフ

リーリストの先頭を指すアドレスを確保している.

4.3.3 マークの付与

本研究では,マークフェーズ時には,マークの付与を行う markObject関数にルートから

直接参照されているオブジェクトを渡すことで,渡されたオブジェクトから再帰的に生きて

いるオブジェクトをマークするようになっている.そのため,ルートから直接参照されてい

る全てのオブジェクトを markObject関数に渡す必要がある.

ソースコード 4.1 にて markObject 関数の擬似コードを示す. markObject 関数内で

は,まずソースコードの 2行目で渡された JSValue型の値がオブジェクトを指すポインタ

なのかどうかを調べる.equalTag 関数は JSValue 型の値の種類を判別する関数である.

JSValue型の値は,データの格納している場所を指しており,下位 3bitでデータの種類を

表す型を保持している.そのため,下位 3 ビットを調べて,オブジェクトを指すポインタ

かどうかを判別する.また,4 行目ではすでにマークされているオブジェクトかどうかも

調べる.markCheck 関数は引数のオブジェクトにマークがあるかどうかを判別する関数で

ある.もし,オブジェクトでは無い場合や,すでにマーク済みのオブジェクトである場合

は,その時点でそのオブジェクトには何も操作しない.そして,マークの付いていない正し

いオブジェクトである場合は,ソースコードの 7行目でオブジェクトにマークを付与する.

objectMark関数は引数のオブジェクトにマークを付与する関数である.マークを付与する

というのは,オブジェクトのヘッダの下から 5bit目のマークビットを 1にするということで

ある.マークを付与したオブジェクトは,さらにそこから辿れるオブジェクトを探す必要が

あるので,ソースコードの 8行目でオブジェクトのヘッダを調べてオブジェクトのデータ型

を調べる.getObjectHeader関数はオブジェクトのデータ型を調べる関数である.オブジェ

クトのデータ型にしたがってそこから辿れるオブジェクトを見つけ,それをmakrObject関

数に渡すことで再帰的に処理していく.STRING型と FLONUM型はこれ以上オブジェク

トを辿らない.ARRAY 型は prop 配列と body 配列の 2 種類の配列のプロパティを辿る.

– 30 –

Page 41: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.3 実装

STRING型,FLONUM型,ARRAY型以外のデータ型のオブジェクトは OBJECT型と

同じ配列プロパティである body 配列を辿る.オブジェクトの持つ numberOfProp プロパ

ティには body配列の長さの値が格納されており,propCount変数に格納する.格納された

値にしたがって配列プロパティを辿る.また,ARRAY型のオブジェクトが持つ lengthプ

ロパティは prop配列の配列の長さが格納されており,その値にしたがって配列プロパティ

を辿る.

– 31 –

Page 42: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.3 実装

ソースコード 4.1 markObject関数の擬似コード

1: static void markObject(JSValue objp) {

2: // オブジェクトを指すポインタか判別

3: if((!equalTag(objp, 0b000)) | (objp == 0))

4: return; // オブジェクトを指すポインタでなければ何もしない

5: if(!markCheck(objp)) // オブジェクにマークがあるかどうか判別

6: return; // オブジェクトにマークがあれば何もしない

7: int i, propCount;

8: objectMark(headNum); // マークビットを 1にする

9: switch(getObjectHeader(objp)) { // オブジェクトの型を調べて型ごとに処理

10: case HTAG STRING: break; // STRING型はこれ以上辿らない

11: case HTAG FLONUM: break; // FLONUM型はこれ以上辿らない

12: case HTAG ARRAY: // ARRAY型は 2つの配列を辿る

13: propCount = objp−>numberOfProp; // 配列の長さを取得

14: for(i = 0; i <= propCount; i++) { // ARRAY型の持つ配列プロパティを辿る

15: markObject(objp−>prop[i]); // markObject関数を呼び出す

16: }

17: for(i = 0; i < objp−>length; i++) { // OBJECT型の持つ配列プロパティを辿る

18: markObject(objp−>body[i]); // markObject関数を呼び出す

19: }

20: break;

21: default: //残りの型はOBJECT型の配列を辿る

22: propCount = objp−>numberOfProp; // 配列の長さを取得

23: for(i = 0; i <= propCount; i++) { //OBJECT型の持つ配列プロパティを辿る

24: markObject(objp−>prop[i]); // markObject関数を呼び出す

25: }

26: break;

27: }

28: }

– 32 –

Page 43: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.3 実装

4.3.4 オブジェクトの辿り方

SSJSVM のそれぞれのルートから直接参照されているオブジェクトの辿り方を以下に

示す.

JavaScriptのグローバル変数

JavaScriptのグローバル変数は,第 2章の 2.2.1で述べたようにグローバルオブジェクト

に格納されている.そのため,グローバルオブジェクトへのポインタをmarkObjectに渡す

だけでよい.

JavaScriptのローカル変数

JavaScript のローカル変数は,第 2 章で述べた関数フレーム内に保存されている.その

ため,制御スタックから指されている全ての関数フレームを辿ることで JavaScripのローカ

ル変数を辿ることができる.

C言語のグローバル変数

C言語のグローバル変数は,SSJSVMのプログラム内で宣言されているグローバル変数

である.オブジェクトを指す変数の型は JSValue 型であるため,JSValue 型で宣言されて

いる全てのグローバル変数を辿る.

C言語のローカル変数

GCは SSJSVMの実行中に,どこで発生するかはわからない.そのため,関数内で GC

が発生した場合は,その関数内で宣言されたローカル変数が指すオブジェクトもマークする

必要がある.また,関数内で関数が呼び出された先で GCが起こった場合は,呼び出し先の

– 33 –

Page 44: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.3 実装

図 4.8 C言語のローカル変数を保存するスタック

関数内のローカル変数だけではなく,呼び出し元の関数内のローカル変数もマークしなけれ

ばならない.そのため,スタックを用いてローカル変数を保存していく.保存する必要のあ

るローカル変数は,グローバル変数同様に JSValue型の変数である.例えば,関数 fの中

で関数 gが呼び出された場合は,図 4.8のように下から関数 fのローカル変数,関数 fが格

納されている場所を示す値,関数 gのローカル変数というふうにスタックに積まれていく.

関数 gから抜け出す際は,関数 fが格納されている場所を示す値にしたがって,スタックを

操作することで関数 fに戻る.

関数呼び出しの返り値を格納するレジスタ

関数呼び出しの返り値が格納されているレジスタは,表 2.1の aレジスタである.特殊レ

ジスタは第 2章で述べたコンテキスト構造体から参照することができるため,コンテキスト

から特殊レジスタが持つオブジェクトにも辿ることができる.

汎用レジスタ

制御スタックに積まれている汎用レジスタはオブジェクトを指している.そのため,制御

スタックにある汎用レジスタが指すオブジェクトを辿る必要がある.

– 34 –

Page 45: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

4.3 実装

文字列テーブル

JavaScript プログラム内の関数に対応するバイトコードの命令列が関数テーブルに格納

されている.関数テーブルにバイトコードの命令列を読み込ませる際に,文字列テーブルに

文字列のデータを読み込むため,文字列テーブルにある STRING型のオブジェクトもマー

クをする必要がある.これは,コンテキストから参照されている命令テーブルから辿ること

ができる.

– 35 –

Page 46: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

第 5章

評価

第 5章では,本研究の GCを持つ SSJSVMについて既存の SSJSVMとオブジェクトを

多数生成するプログラムの実行時間を比較した.その結果,本研究の GCを持つ SSJSVM

のほうが既存の SSJSVMより遅かった.その原因について考察し,本研究の GCを高速化

する方法について検討する.

5.1 検証方法

本研究では,以下の2つの点について BoehmGCを利用する既存の SSJSVMとマークス

イープ GCを実装した新たな SSJSVMの 2つの処理系を比較して検証する.また,検証を

行う際は,GCを公平に動かすために,本研究の GCを持つ SSJSVMのヒープ領域の大き

さを固定する.検証を行った環境は,Ubuntu14.04,Intel Core i5 3.3GHZ,gcc 4.8.4 で

ある.

• ごみのオブジェクトを多数生成するプログラムの実行時間

• マークスイープ GCを実装した SSJSVMのプログラムの実行時間の内訳

最初にごみのオブジェクトを多数生成するプログラムの実行時間を検証する.BoehmGCで

は任意のヒープ領域の大きさを指定できない.そのため,本研究の GCを持つ SSJSVMは,

BoehmGCで利用されたヒープ領域の大きさに合わせてヒープ領域の大きさを固定する.今

回はヒープサイズを,BoehmGC に合わせて 479232Byte とする.検証に用いるプログラ

ムをソースコード 5.1に示す.このプログラムは,外側 forループで生成したオブジェクト

– 36 –

Page 47: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

5.1 検証方法

をグローバル変数に格納し,内側 forループで次々と新しいオブジェクトを生成するプログ

ラムである.こうすることで,外側 forループで生きているオブジェクトを,内側 forルー

プで死んでいるオブジェクトを多数生成するオブジェクトである.また,ヒープ領域を生き

ているオブジェクトと死んでいるオブジェクトで断片的に利用する.このプログラムの内側

forループの回数を 1000回から 6000回まで 1000回ずつ増やして検証を行う.ループの回

数を増やす度に,ごみのオブジェクトが生成される回数が増える.

続いて,マークスイープ GCを実装した SSJSVMのプログラムの実行時間の内訳を調査

する.今回調査する実行時間の内訳は,プログラムの全実行時間,メモリ割り当てと GC

の時間,メモリ割り当ての時間である.検証に用いるプログラムはソースコード 5.1 であ

る.ただし,内側 for ループを 5000 回に固定する.検証のために,本研究の GC を持つ

SSJSVM のヒープ領域を,50KByte から 850KByte まで 200KByte ずつ増やして検証す

る.また,ヒープ領域を 479232Byteに固定した先ほど検証に用いた既存の SSJSVMの実

行時間も示す.

今回の研究では,SSJSVM内で生成するオブジェクトに対応する GCを実装した.その

ため,既存の SSJSVM はオブジェクトのメモリ割り当てを BoehmGC で処理をして,そ

の他のメモリが必要な処理は malloc関数を用いてメモリ割り当てを行う.また,本研究の

GC を持つ SSJSVM についても,オブジェクトのメモリ割り当て以外は全て malloc 関数

を用いてメモリ割り当てを行う.オブジェクトの割り当てに使った全てのメモリ領域の大き

さ,malloc 関数を用いて確保した全てのメモリ領域の大きさの関係を図 5.1 に示す.この

図は,縦軸が利用したメモリ領域の大きさで横軸がソースコード 5.1の内側 forループの回

数である.また,この図で GC が発生した時に生きているオブジェクトが使用しているメ

モリ領域の大きさは 8KByteほどである.さらに,オブジェクトの割り当てが起きた回数と

malloc関数を用いてメモリ領域を確保した回数を図 5.2に示す.

– 37 –

Page 48: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

5.1 検証方法

ソースコード 5.1 JavaScriptのソースコードの例

1: var Cell = function(val, next) {

2: this.val = val;

3: this.next = next;

4: }

5: var head = new Cell(0, null);

6: for (i = 0; i < 10; i++) {

7: head = new Cell(i, head);

8: for (j = 0; j < N; j++)

9: new Cell(0, null);

10: }

図 5.1 オブジェクトの割り当てと malloc関数で使用したメモリ領域の大きさ

– 38 –

Page 49: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

5.2 検証結果

図 5.2 オブジェクトの割り当てと malloc関数でのメモリ割り当ての回数

5.2 検証結果

ごみのオブジェクトを多数生成するプログラムを 2 つの処理系で比較した結果を図 5.3

に示す.この図では,青色の線が既存の SSJSVM,オレンジ色の線が本研究の GC を持

つ SSJSVMである.図より,本研究の GCを持つ SSJSVMのほうが遅いということがわ

かる.

本研究の GC を持つ SSJSVM の,実行時にかかる全実行時間,メモリ割り当てと GC

の時間,メモリ割り当ての時間,さらに既存の SSJSVMでの実行時間をグラフにしたもの

を図 5.4に示す.この図では,青色の線が本研究の GCを持つ SSJSVMの全実行時間,オ

レンジ色の線がメモリ割り当てと GC の時間,灰色の線がメモリ割り当て時間を示してい

る.また,緑色のバツ印は既存の SSJSVMを示している.緑色のバツ印が 1点だけなのは,

BoehmGCではヒープ領域の大きさを任意の大きさに固定できないためである.そのため,

BoehmGC で使われたヒープ領域の大きさから,本研究の GC を持つ SSJSVM のヒープ

領域の大きさを決めている.また,図 5.4の実験に用いたプログラムを実行したときの,本

– 39 –

Page 50: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

5.2 検証結果

研究の GCを持つ SSJSVMのヒープ領域の大きさに対する GCの回数を表 5.1に示す.図

5.4と表 5.1より,メモリ割り当てと GCにかかった時間とメモリ割り当てにかかった時間

の差が小さいことがわかった.また,メモリ割り当ては GCよりも時間がかかっていること

がわかった.

図 5.3 本研究の GCを持つ SSJSVMと既存の SSJSVMの実行時間の比較

表 5.1 ヒープ領域の大きさに対する GCの回数

ヒープ領域の大きさ(KByte) 50 250 450 650 850

GCの回数 131 21 11 8 6

– 40 –

Page 51: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

5.3 考察

図 5.4 本研究の GCを持つ SSJSVMの実行時間の内訳と既存の SSJSVMの実行時間の比較

5.3 考察

検証結果より,本研究の GCを持つ SSJSVMが既存の SSJSVMより遅いということが

わかった.GCの性能改善を狙って既存の SSJSVMに保守的ではないマークスイープ GC

を実装したが,既存の SSJSVMより実行時間が遅くなった.図 5.4から,メモリ割り当て

と GCにかかった時間とメモリ割り当てにかかった時間の差は小さいのに対して,メモリ割

り当てにかかった時間は大きいことがわかる.そのため,メモリ割り当てに多くの時間がか

かってしまい遅くなったということがわかる.

本研究の GCのメモリ割り当ては,プログラムから要求されたメモリ領域以上の領域を,

フリーリストを先頭から探して割り当てる割り当て方式である.そのため,プログラムから

メモリの要求があれば,毎回フリーリストの先頭から必要な空き領域が見つかるまで探索し

ていくため,メモリ割り当てに時間がかかる.そこで,メモリ割り当てが起こる度に必要な

空き領域が見つかるまでフリーリストを辿った回数を調べた.図 5.5は,オブジェクトにメ

モリを割り当てるために,必要な空き領域が見つかるまでフリーリストを辿った回数を示し

– 41 –

Page 52: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

5.3 考察

ている.縦軸はフリーリストを辿った回数,横軸はオブジェクトが割り当てられた回数を示

している.また,この図は本研究の GCを持つ SSJSVMのヒープ領域を 25KByteに固定

し,用いたプログラムはソースコード 5.1の内側 forループの回数を 20回で固定したプロ

グラムである.この図では,合計 2回 GCが起きている.1回目の GCが起きるまでは,オ

ブジェクトのメモリ割り当ては常にフリーリストの先頭から行われるので,フリーリストを

辿る回数は 1回である.1回目の GCが起こると,必要な空き領域をフリーリストの先頭か

ら順に探して割り当てるので,オブジェクトのメモリ割り当てが行われる度にフリーリスト

を辿る回数が増えていく.そして,フリーリストに必要な空き領域が無ければ GCが再び発

生する.図では,オブジェクトを割り当てる回数が 550 回目ほどに達したときに 2 回目の

GCが発生しており,その時点でフリーリストが新しく作られるので,フリーリストを辿る

回数は一時的に減る.しかし,2回目の GCが起きてから徐々にフリーリストを辿る回数が

増えていく.この図より,GCが起こるまでフリーリストを辿る回数が増えていくので,フ

リーリストによるメモリ割り当てに時間がかかることがわかる.

図 5.5 オブジェクトが割り当てられる度にフリーリストを辿る回数

– 42 –

Page 53: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

5.4 今後の課題

5.4 今後の課題

本研究で実装した GCはメモリ割り当てが遅いことがわかった.そのため今後の課題とし

ては,メモリ割り当てを高速化することが挙げられる.そのための方法としては,フリーリ

ストによるメモリ割り当てを高速化する方法と高速なメモリ割り当てを行う世代別 GC を

実装する方法の 2通りある.

例えば,フリーリストの高速化はフリーリストを空き領域の大きさによって分けて複数用

意する方法がある.似たような大きさの空き領域どうしを一つのフリーリストにして,空き

領域の大きさごとに異なったフリーリストを用意する.こうすることで,プログラムからメ

モリの要求があれば,要求された領域の大きさによって辿るフリーリストを変えることで,

フリーリストを辿る時間を短縮することができる [8].

また,メモリ割り当てが高速な世代別GCを実装する方法もある.世代別GCとは,オブ

ジェクトに年齢の概念を付与し,多くのオブジェクトは生成されてすぐに死に,長く生き残

るオブジェクトは少ないということを前提に考えられたアルゴリズムである.具体的には,

GCが起こる度に生き残ったオブジェクトは中々死なないので,GCの頻度を下げ,逆に生

成されたばかりのオブジェクトに対しては頻繁に GCすることで処理速度を向上させている

GCアルゴリズムである.また,世代別 GCはマークスイープ GCやコピー GCなどの基

本アルゴリズムの GC を組み合わせて作られた GC アルゴリズムであり,メモリ割り当て

はメモリ割り当ての速い GCアルゴリズムを利用して,GCの処理にはヒープ領域の使用効

率の良い GC を利用する.このように場面によって適用する GC アルゴリズムを変えるこ

とで処理速度を向上させている.

– 43 –

Page 54: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

第 6章

関連研究

GCのアルゴリズムは,50年以上昔から長きに渡って研究が続けられている.長く研究さ

れている分野なので,GCのアルゴリズムには様々なものが存在する.本研究で扱ったマー

クスイープ GCは世界で初めて生まれた GCアルゴリズムである.マークスイープ GCは,

プログラム中で使用されるオブジェクトが多ければ多いほど,マークにかかる時間が増えて

しまって効率が悪い.そのため,オブジェクトを多く生成するような大きなプログラムとは

相性が悪い.

Rubyというオブジェクト指向スクリプト言語も,以前のバージョンではマークスイープ

GCが実装されていた.しかし,オブジェクト指向スクリプト言語が大規模なプログラムで

も利用されはじめるようになって GCの遅さが顕著になった.そこで,マークスイープ GC

より格段に速い世代別 GC が実装された.Ruby の GC をマークスイープ GC から世代別

GC にすることで,GC の処理時間が最大で 92%,プログラムの実行時間が最大 50%短縮

したという結果が出ている [7].この研究により,GCの処理時間が大幅に減っているので,

世代別 GC が有用であることがわかる.現在では,世代別 GCが実装されている処理系も

多くなっている.特に,V8 JavaScriptエンジンで動作する Node.jsなどはこの世代別 GC

を採用しており,非常に高速な処理を行う処理系である.

– 44 –

Page 55: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

第 7章

おわりに

本研究では,既存の BoehmGC ライブラリを使った SSJSVM の GC の性能を調査し,

GCの性能が悪いことを突き止めた.さらに,GCの性能改善を狙って SSJSVMにマーク

スイープ GCを実装した.しかし,実装した GCは既存の SSJSVMの GCよりも遅いこと

がわかった.原因としては,本研究の GCではメモリ割り当てに時間がかかっているためと

考えられる.

SSJSVMのプログラムの中では malloc関数を用いて様々な所でメモリの割り当てを行っ

ている.しかし,今回はその中でも SSJSVM 内のオブジェクトを GC の対象としている.

そのため,今後GCの対象になっていない部分についてもGCの対象にすることで,より多

くのメモリ領域を使用するプログラムも実行することができるようになる.そのため,今後

の課題として,プログラムが利用する全てのメモリ領域を GCの対象とする必要がある.ま

た,今回の研究ではGCの性能改善を狙って新たにマークスイープ GCを実装したが,本研

究の GCを持つ SSJSVMは,既存の BoehmGCを利用している SSJSVMより処理速度が

遅いことがわかった.原因は,本研究の GCを持つ SSJSVMのメモリ割り当てにかかる時

間が遅いことが挙げられる.そのため,フリーリストを高速化するか,メモリ割り当てを高

速に行う GCアルゴリズムを実装することで,性能を向上させることが今後の課題である.

– 45 –

Page 56: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

謝辞

本研究を進めるに当たり,研究指導及び論文の執筆に関して,丁寧なご指導をいただいた

准教授の鵜川始陽先生に感謝の意を表し,厚く御礼申し上げます.また,研究活動だけでな

く,就職活動や研究室活動など様々なご指導を頂いたことを心より感謝致します.本論文の

副査として貴重なご意見をいただいた教授の福本昌弘先生,准教授の松崎公紀先生に感謝致

します.また,日々の研究室活動にて輪講などで様々な意見をいただいた鵜川研究室の皆様,

松崎研究室の皆様に感謝致します.

最後に,私の大学生活を支えてくれた両親にも感謝致します.また,大学生活にて 4年間

お世話になりました情報学群の教職員の皆さんに感謝します.ありがとうございました.

– 46 –

Page 57: サーバサイド向け JavaScript ためのマークスイープごみ集めの … · 要旨 サーバサイド向けJavaScript 処理系の ためのマークスイープごみ集めの

参考文献

[1] 漆原 明博,岩崎 英哉,鵜川 始陽,サーバサイド向け JavaScript 処理系における Just

In Time コンパイラの実装,第 16 回プログラミング及びプログラミング言語ワーク

ショップ,2014.

[2] 中村 成洋,相川 光,ガベージコレクションのアルゴリズムと実装,秀和システム,

2010.

[3] NAKAMURA Minoru,「Boehm GC ライブラリを使って C/C++ でもガベージ

コレクションしよう」,[online]http://www.nminoru.jp/~nminoru/programming/

boehm-gc2.html(参照 2015-7-26),2002.

[4] 漆原 明博,サーバサイド向け JavaScript処理系における Just In Time コンパイラの

実装,電気通信大学大学院情報理工学研究科 情報・通信工学専攻修士論文,2014.

[5] 高田 祥,鵜川 始陽,中野 圭介,岩崎 英哉,JavaScript仮想機械における Quickening

の効果,第 15回プログラミング及びプログラミング言語ワークショップ,2013.

[6] Andrew W.Appel 著,神林 靖,滝本 宗宏 訳,最新コンパイラ構成技法,翔泳社,

2009.

[7] 木山 真人,オブジェクト指向スクリプト言語 Rubyへの世代別ゴミ集めの実装と評価,

情報処理学会論文誌:プログラミング,Vol.43,No.SIG 1(PRO 13),2002.

[8] Richard Jones,Antony Hosking,Eliot Moss,The Garbage Collection Handbook,

Chapter 7,CRC press,2012.

– 47 –