関西闇Ruby会議とFFI::Ruby
関西闇Ruby会議で発表しました。
内容は最近使う機会の増えたruby-ffi(フィッフィ)の紹介。 その時のスライドです。
ちょっとまとめきれなくて最後のほうにごちゃごちゃと書いてしまっていますが、C/Ruby間で独自の型変換を作れるとあったので試しにVALUE型をRubyのオブジェクトに変換するffi-rubyというのを作ってみました。 実用的なかおりがするけどあんまり使い途ない。
VALUE型の変換これであってるのかなぁ。簡単な恒等性のテストにはパスしてるみたいだけど。
Mac OS X でFrama-Cを使ってRubyを静的解析するメモ
@ikegami__さんのFrama-Cを使った実験が面白そうなので試してみた。
試験環境はMacBookAir/Mac OS X Lion/ruby1_9_2
インストール
$ brew install ocaml
$ wget http://frama-c.com/download/frama-c-Nitrogen-20111001.tar.gz
$ tar zxf frama-c-Nitrogen-20111001.tar.gz
$ cd frama-c-Nitrogen-20111001
$ ./configure --prefix=...
$ make
$ make install
使ってみる
Rubyのソースツリーに移動する。
$ cd ruby
$ ./configure
記事を参考に、.ext/include/ARCH_NAME/ruby/config.h に以下の行を追加。
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif解析対象ファイルの一覧を作っておく。
$ vi mainobj
array.c bignum.c class.c compar.c complex.c dir.c dln_find.c enum.c enumerator.c error.c eval.c load.c proc.c file.c gc.c hash.c inits.c io.c marshal.c math.c node.c numeric.c object.c pack.c parse.c process.c random.c range.c rational.c re.c regcomp.c regenc.c regerror.c regexec.c regparse.c regsyntax.c ruby.c safe.c signal.c sprintf.c st.c strftime.c string.c struct.c time.c transcode.c util.c variable.c compile.c debug.c iseq.c vm.c vm_dump.c thread.c cont.c
一覧は、common.mk中のCOMMONOBJSを参考にしている。
Frama-C Nitrogen 20111001 で ruby-1.9.2-p290 を検査するときにどうにもならなさそうな事であげられているファイルのいくつかは、直接コンパイルされることを想定して書かれていないので失敗するようだ。
解析開始
$ frama-c \
-cpp-extra-args="-U__BLOCKS__ -DRUBY_EXPORT -I./.ext/include/ARCH_NAME -Iinclude" \
-machdep x86_64 \
-save ruby.session \
`cat mainobj`
-U__BLOCKS__はSnowLeopardから導入されたBlocks(Cの文法を拡張している)を無効にするため。これを無効にしないとparseが失敗する。
-machdep x86_64はARCH_NAMEにあわせたものを$ frama-c -machdep helpの結果から選ぶ。
$ frame-c -load ruby.session -metrics
...(ry)...
[metrics] Syntactic metrics
-----------------
** Defined functions (6297):
...(ry)...
** Undefined functions (297):
...(ry)...
** Potential entry points (1694):
...(ry)...
SLOC: 144947
Number of if statements: 25635
Number of assignments: 40691
Number of loops: 3651
Number of calls: 31176
Number of gotos: 7496
Number of pointer access: 50736
$ frame-c -load ruby.session -users -main rb_ary_new
...(ry)...
[users] ====== DISPLAYING USERS ======
ary_alloc: rb_newobj
ary_new: rb_newobj ary_alloc
rb_ary_new2: rb_newobj ary_alloc ary_new
rb_ary_new: rb_newobj rb_ary_new2 ary_alloc ary_new
====== END OF USERS ==========
参考:
CHM viewer on terminal
MacBookPro壊れてLinux使ってた時にGUIのものしか見当たらなかったので。
名前も未定です。
Rubyリファレンスマニュアルのchmは文字コード変なので悲しい。
Guardを使ったCoffeeScript開発
guardはファイルの変更を検知して、決められたタスクを実行するためのツールである。 Mac OS X / Linux / Windows それぞれのファイルシステム変更検知APIに対応しており、それ以外のプラットフォームではポーリングにて変更検知を行う。
$ gem install rb-fsevent # Mac OS X の場合
$ gem install guard
$ gem install guard-coffeescript
$ guard init coffeescript
$ vi Guardfile
guard 'coffeescript', :input => 'src/', :output => 'dist/'
$ guard start
こうすることで、src/ 以下の.coffeeファイルに変更があった場合即座にコンパイルされ、dist/以下に.jsファイルが生成される。
なお、rb-fseventは入れなくても動くがその場合はポーリングになる。
Mac以外のOSではこうするらしい。
$ gem install rb-inotify # Linuxの場合
$ gem install rb-fchange # Windowsの場合
guard-coffeescriptの他にも様々なguardがあるようです。
参考:
CoffeeScript時代のモジュールシステムの選び方ガイド
猫も杓子もCoffeeScriptの世の中、CoffeeScriptに手を出してしまったがために(JavaScriptの世に)帰らぬ人となりつつある人はたくさんいると思う。 僕も最近CoffeeScriptに手を染め五分で帰り途を見失ってしまった。
CoffeeScriptの編集にはujihisa氏のshadow.vimが便利だ。 shadow.vimを手短に紹介すると、main.js を開いて編集していると思ったら実はmain.js.shd(中身はCoffeeScript)を編集していて、気づいた時にはすでにmain.js.shdのコンパイル結果がmain.jsに保存されている、というvim-pluginである。
さて、JavaScriptを本格的に使うには、モジュールシステムを避けて通る事はできない。 グローバル変数を多用することも許されているJavaScriptでは、ライブラリによるオブジェクト空間の汚染は予測できない結果を引き起こしかねない。
モジュールシステムは未だ黎明期なので、本稿ではベストのものを選択するよりは、CoffeeScriptで書くクライアントサイド(以下CS)コードをサーバサイド(以下SS)でテストすることを念頭に、モジュールシステムの選び方を検討する、という方向で行こうと思う。 なお、ブラウザによる互換性は面倒くさいのでチェックしない。どうせやってることは一緒なのでいざとなれば解決可能な問題だし、各自で使用前にチェックしてください。
CommonJS
JavaScriptの処理系はちょっとリストアップするのが大変なほどある。
これらでばらばらのライブラリAPIを使われてはたまらないので、標準を決めようという事で、CommonJSと呼ばれる標準のようなものがあるらしい。 CS-APIではまだ存在する実装をまとめただけのような雰囲気もあり、CommonJS準拠だから選ぶ、ということにはならないが、 ありがたいことに、CommonJSに参加?しているプロジェクト一覧があり、これをベースに見ていくと楽できそうだ。
リストのうち、ブラウザ向けのものは
以下はリストには載ってないが見つけたやつ。
モジュールシステムについては、Modulesに関係する仕様と提案があり、これを参考にする。
Modules
おおまかに言うと、Modules/1.0では以下のようなrequireとexports変数を使ったオブジェクトのエクスポートを要求している。
// math.js
exports.add = function(x, y) { return x + y }
// increment.js
var add = require('math').add
exports.increment = function(val) {
return add(val, 1)
}
// main.js
require('increment').increment(2) //=> 3SSの処理系ではこれは広くサポートされているようだ。
Modules/AsynchronousDefinition (AMD)
CSでは、スクリプトの読み込み方法が限られている(scriptタグの追加かXHRによる読み込み)し、同期的読み込みを前提とした上記のような定義方法は実用的ではない。
そこでModules/Transport/* という名前でいくつかの提案がされている。
歴史的な経緯はよくわからないが、Modules/Transport/Aの実装であったRunJSはModules/Transport/Cの実装であるRequireJSへと名前を変え、
Modules/Transport/CはModules/AsynchronousDefinition(以下AMD)へと昇格?しているらしい。
AMDは以下のような形式で、他のものと比べて暗黙的な変数の導入がなく、スジがよいように思える。
これがデファクトになっていくのだろうか。
// define(moduleId?, deps?, factory function / object to be exported)
// math.js
define({
add: function(x, y) { return x + y }
})
// increment.js
define('increment', ['math'], function(math) {
return {
increment: function(val) {
return math.add(val, 1)
}
}
})CoffeeScriptとの相性もよい。これは今回は重要なポイントだ。参考までにCoffeeScript版も書いておく。
// increment.coffee
define ['math'], (math) ->
increment: (val) -> math.add(val, 1)Modules/1.xとの互換性を考慮した
// increment.js
define('increment', ['math', 'require', 'exports'], function(math, require, exports) {
// これより内側がModules/1.xの定義そのままで動く
exports.increment = function(val) {
return require('math').add(val, 1)
}
})といった書き方も用意されているようだ。
採用しているライブラリは
- RequireJS
- Yabble(partial)
- OzJS
- Nodules
- Dojo(1.6で試験的に導入)
- Teleport
- JSLocalnet
- PINF JS Loader(partial)
- backdraft
など。
Modules/Wrappings
//increment.js
module.declare(['math'], function(require, exports, module) {
return {
increment: function(val) {
return require('math').add(val, 1)
}
}
})あんまり違いがわからないが、ポイントはfactory関数の引数がrequire, exports, moduleの三つで固定されていることだろうか。その名前から、Modules/1.xとの互換性目的のものと思われる。
exportsを使ってもよいし、factory関数の返り値としてオブジェクトを返せばそれがそのままモジュールになる。
Modules/Async/A
AMDに対応したローダーの仕様はModules/Async/Aに書かれている。 といっても、Yabbleの実装(下記)をそのまま書いてあるだけのような気がするが。 対応ライブラリはYabbleのみしか書かれていない…え…
結局のところ、AMDはdefineの文法的形式が決まっているだけで、ローダにはまだ決定打がない。 コードを書く際はローダの呼び出しを最小限にするのが良さそうだ。
この辺がCommonJSの限界のようなので、あとは各々の実装を見ていくのがよさそうだ。
Yabble
// increment.js
require.define({
increment: function(require, exports, module) {
var math = require('math')
exports.increment = function(val) {
return math.add(val, 1)
}
}
}, ['math'])
// main.js
require.ensure(['increment'], function(require) {
require('increment').increment(2); // 3
});第一引数に依存するモジュールを、第二引数にcallbackを指定する。モジュールのロードが完了すると、callbackが呼ばれる。
テストコードも豊富でなかなか完成度の高いコードだ。
しかし、SSで使われることは想定されておらず、本体に手を入れずに使うことはできなさそう。
SSのテストコードでは利用する機能を搾って、同じインターフェースを持つ他のライブラリに丸投げする事が可能だ。
(例えばNodulesは、require.ensureを持っている)
Nodules
//main.js
require.ensure(['increment'], function(require) {
require('increment').increment(2); // 3
});$ node PATH_TO_NODULES/lib/nodules.js main.js
こんな感じで。
Nodulesの機能のこれはごく一部で、この他に
- HTTP上のjsをrequireする(そのためのrequire.ensure)
Packages/Mappingsの実装
など。
コマンドラインからの起動が必要なのはマイナスポイント。 あと、defineの第一引数を指定すると、ファイル名(フルパス)と違うと怒られた。
RequireJS
同じものがRequireJSではこうだ。
require(['increment'], function(increment) {
increment(2); // 3
});シンプルすぎて泣ける。かっこいい。 なお、defineは、一つのファイルに複数のモジュールを記述することを許しているがその場合は、
//libs.js
define('math', { … })
define('increment', ['math'], { … })
//main.js
require(['require', 'libs'], function(require) {
require('math').increment(2); // 3
});というように多段にしてrequireすればよい。
RequireJSはSSでの(node, rhinoに対応)実行も行えるようになっており、
$ PATH_TO_REQUIREJS/bin/x main.js
とすればいい。この時、engine-nativeのrequire関数はオーバロードされる。 ただこの方法だと、CoffeeScript中のrequireなどは置き換えられないため若干使いづらいし、そもそもrequireを汚染されるのは気持ちのいい物ではない。
これに関しては、wrapperを書く事で、通常のライブラリと同様読み込むことができるようだ。
// requirejs-node.js
(function() {
var read = require('fs').readFileSync
var run = require('vm').runInNewContext
var env = {
importScripts: function(url) {
run(read(url), env)
}
}
var code = read(require.resolve('require'))
run(code, env)
exports.require = env.require
exports.define = env.define
}).call()
// main.coffee
rjs = require 'requirejs-node'
rjs.require ['your_library'], (library) -> ...rjs.requireで読み込まれるライブラリ内ではrequire = rjs.require, define = rjs.define となる。
Dojo
Dojoでは1.6以降AMD形式のライブラリを提供していく予定らしい。 Loaderは提供しないので、今回は関係ない。
LoaderにはbdLoad / RequireJS を使えとのこと。
backdraft / bdLoad
backdraft frameworkの中のbdLoadというのがそれらしい。
- AMD-compliant / RequireJS compatible
- サイズが小さい
のが売りだそうだ。
RequireJSのテストコードがレポジトリに含まれていることから、RequireJSのよりよい実装と考えてもよさそうだ。
NodeJS用のインターフェースもデフォルトで用意されている。
上記RequireJSではwrapperを書いたが、bdLoadではデフォルトでほぼ同じ様になる。
// bdload-node.coffee
bdLoad = require('node').boot()
bdLoad.require
paths:
mylib: './mylib/lib'
bdLoad.require ['mylib/mylib'], (mylib) -> ...これはかなりいい。RequireJSを選ぶ理由はほぼない気がする。RequireJSはリファレンスマニュアルがかっこいい。
ちなみに、backdraftレポジトリをcloneしようとしたら、AAを用いたCAPTCHAのようなものが表示され、フォントが違うので読めなくてログインできない。CAPTCHAは見る価値あり。
OzJS
作者(dexteryy)はtudou.comのフロントエンジニアらしい。 スライドは中国語で詳しくはわからないが、かなり詳細に論じている様子が伺える。 他のライブラリに比べると圧倒的にサイズが小さいし、TUICompilerというのを使って静的に複数のスクリプトをまとめることができるようだ。
ただし、NodeJSからは使えなかった。
あとoz.defという名前で微妙にAMDと互換性がないので、気にする人はdefine = oz.defしてそっちを使うのがよいかもしれない。
// increment.js
var define = oz.def
oz.def('math', 'math.js')
define('increment', ['math'], function(math) {
return {
increment: function(val) {
return math.add(val, 1)
}
}
})
// main.js
oz.require(['increment'], function(increment) {
increment.increment(2) //=> 3
})FlyScript
Modules/Wrappingsを採用しているFlyScriptだが、何があったのかgithubのレポジトリが消えている。
作者の他のレポジトリも丸々ないので公開やめたのかな…
SeaJS
Modules/Wrappingsなのでこんな感じ。
//increment.js
define(['math'], function(require, exports, module) {
return {
increment: function(val) {
return require('math').add(val, 1)
}
}
})
//main.js
seajs.config({
base: './...',
alias: {
//...
}
})
seajs.use(['increment'], function(increment) {
increment.increment(2) //=> 3
})SSでは動かなかった。 Backbone.js系のライブラリを添付してくれていて助かるが、必ずmoduleId.jsを読みに行ってしまうみたい。 これは、production環境でファイルをまとめたい時などには困るだろう。 お手軽にBackbone.jsで遊ぶ専用か。
JSLocalnet
- ライセンスがGPLv3/プロプライエタリ
- XHRにしか対応してない
- IE8非対応
- コメントがスペイン語
- レポジトリがhg
- テストコード一切無し
と、異なる文化圏にあるようでちゃんと見るのやめました。
PINF JS Loader / bravojs
Modules/2.0!
Modules/Wrappingsとの違いがよく分からない…
未実装の部分が多いが、完成するとかなりの処理系(JetPack, NodeJS, browsers…) にまたがって共通のモジュールシステムを提供することになるようだ。
Modules/2.0提案用のリファレンス実装という色が濃く、unstable感が高いので今回はパス。
curl.js - updated on 2010/05/05
curl.jsはcujo platform用のAMDローダ。 以前まではdojoのローダを使っていたようだが、今はAMDを使うようになったamdブランチがあるようだ。 まだリリースされて一ヶ月とあまり情報もないので見逃していた。 SSでは動かない。
- 素直にAMDを実装
next,thenなど独自機能- ‘text!xxxx.text’ でテキストファイルをロード
- ‘js!xxxx.js’ でnon-AMDなjsをロード
といった感じ。特に最後の拡張は、AMD非対応jsが多い現状を考えると面白い。
作者のスライド(オススメ)によれば、AMDではrequireはThe Wild Westだという。
しかし、requireの呼び出しはコードの1%にも満たないので、もっとやれ!ということのようだ。
curl({
baseUrl: '...',
paths: ['.']
}, {})
require(['increment'], function(increment) {
increment.increment(2); // 3
});
// 別の書き方
require(['increment'], (function(increment) {
increment.increment(2); // 3
})
.next(['js!jquery.js!order', 'js!zoom.js!order'])
.then(function() {/* success */}, function(e) {/* error */});サイズ
CSで利用する際に気になるのはサイズだが各ライブラリの主要ファイルのサイズを以下の方法で調べた。
$ uglifyjs -nc --unsafe < xxx.js | wc -c
$ uglifyjs -nc --unsafe < xxx.js | gzip -c | wc -c
OzJSがもっとも小さく、RequireJSが最も大きいがその差は数倍程度の開きでしかなく、あまり大きな要素にはならないように感じた。 まとめの項に表を示す。
まとめ
CSのモジュール定義はAMDでほぼ確定、ローダは標準なしということで、 様々なモジュールローダを見て来たが、SS/CSで動くよう作られたライブラリはやはり少なかった。 現時点では、SS/CSで使うライブラリをわけるのが選択の幅を狭めない妥協点だ。
| library | license | server-side | size | gziped | nank |
| RequireJS | MIT / mBSD | ? | 16486 | 5788 | ★★★☆☆ |
| bdLoad | BSD | o | 11221 | 4714 | ★★★★★ |
| OzJS | MIT | x | 3143 | 1543 | ★★★★☆ |
| SeaJS | MIT | x | 5489 | 2319 | ★★☆☆☆ |
| Yabble | MIT | x | 6635 | 2468 | ★★★★☆ |
| bravojs | MIT | o | 8646 | 2671 | ★★★☆☆ |
| curl.js | MIT | x | 4627 | 2247 | ★★★★☆ |
| JSLocalnet | GPLv3 / Proprietary | x | - | - | - |
| FlyScript | MIT | - | 8594 | 3831 | - |
| Nodules | mBSD / AFL2.1 | o | - | - | - |
PINF JS Loader / bravojs の組み合わせは今回の様な用途を本気で目指したものであり、今後注視しておきたいが、今変化の直中であり手を出しづらい。
また、中国製のライブラリがいくつか(OzJS, SeaJS)見受けられ、中国でJavaScriptがキてるのが感じられる。 この組み合わせは強そうだ。
バランスがいいと感じたのはbdLoadであったが、さらに踏み込んで使いたい場合はOzJS / curl.js もよい選択だと思う。
おまけ
名前が挙ってたので調べたけど、関係なさそうなやつ。
Teleport
teleportは、browserでの開発にNodeJSのエコシステムを持ち込むものらしい。
$ npm init # package.json作成
$ npm link
$ vi index.html
$ teleport activate
とすることで、開発中のpackageにhttp://localhost:4747/PACKAGE_NAME/でアクセスできるようになる。
http://localhost:4747/teleport-dashboard/でnpm管理下のパッケージ一覧が見られる。
browser上でrequire('...')などとすると、npmパッケージをロードすることができる。
この時、Modules/1.x 形式のモジュールを、defineでくるんでCSに送信する。
また、require/define がすでに定義されている場合は、上書きしないような配慮がされている。 うまく開発プロセスに組み込めば、ブラウザによるテストも楽になりそう。
リリース時には、$ teleport bundle PACKAGE_NAME/app とすることで、必要なパッケージを展開?してくれるようだが、これはバグで動かなかった。
Transporter
Transporterでは、Modules/1.0モジュールを、様々なtransport形式でCSに提供するSSの仕組みを提供している。
CS-APIは、require.ensure / defineを使うようだが、非同期読み込みには対応しておらず、自分であらかじめscriptタグで読み込んでおく必要があるようだ。
利点がわからない…誰か教えて…
参考:
- CoffeeScript
- azer/jsbuild - GitHub
- vcs-localnet - CommonJS in browser-side / CommonJS en el navegador - Google Project Hosting
- pinf/loader-js - GitHub
- RequireJS
- jbrantly/yabble - GitHub
- bravojs - Modules/2.0 for the Browser - Google Project Hosting
- dexteryy/OzJS at master - GitHub
- Modules/Transport - CommonJS Spec Wiki
- CommonJS: JavaScript Standard Library
- Modules - CommonJS Spec Wiki
- Modules/Async/A - CommonJS Spec Wiki
- Head JS :: The only script in your HEAD
- SeaJS - 海纳百川,有容乃大。
- backdraft browser application framework - home
- ujihisa/shadow.vim - GitHub
- kriszyp/nodules - GitHub
- Unbeatable JavaScript Tools - The Dojo Toolkit
- Gozala/teleport - GitHub
- kriszyp/transporter - GitHub
- Dojo 1.6 Release Notes — The Dojo Toolkit - Reference Guide
- FlyScript - It’s a CommonJS Thing
- Modules/Wrappings - CommonJS Spec Wiki
- unscriptable/curl - GitHub
- curl.js – yet another AMD loader | Unscriptable.com
- cujo at amd from unscriptable/cujo - GitHub
- unscriptable/cujo - GitHub
- Using AMD loaders to write and manage modular javascript
iPhoneアプリPhotosynthで鴨川デルタを撮影
こういうエントリはほとんど書かないんだけど、Photosynthはそのはじめのころからずっと見ていたし、首の消えてしまったおじさん(プライバシーに配慮して)の向うには出町ミスドがあるし、なによりPhotosynthが素晴らしかったので。
iPhone持ってる人は一度は試してみるべき。共有しなければアカウント作成とか要らない。
一部破綻が見られるけど、iPhoneで誰でも撮れるというのはかなりインパクト大きい。 bing map今からでもGoogleMapsと張り合える。
しかし相変わらず弱そうなソーシャルパートw 外部にライセンスするか、api公開していい会社買った方がいいものできそう。
Mac OS X で変な漢字を探す亖つの方法
元々の話題は、火が三つの漢字を見た事あるけど見つからない、というものから。
1. 手書き文字入力 / ⌃⌥ Space / Ctrl+Shift+Space

詳しくは下記URLの記事を参照。
2. ⌃1, ⌃2 / Ctrl+1, Ctrl+2
対象となる文字を選択後、Ctrl+1を押す
対象となる文字を選択後、Ctrl+2を押す
3. 文字ビューア
「文字ビューアを表示」を選択
記号など探すには便利。地道に探す。

4. CHISE/漢字構造情報データベースを使う
CHISE IDS Findを使って検索するか、CHISEプロジェクトからデータベースをダウンロードして自分で探す。
今回のように三つの文字が並んでいる漢字を探す場合、例えば”森”、という字なら、
… 森 ⿱木⿰木木
という感じの表現で入っているはずなので、UTF-8を正しく扱えるシステム上で /\t⿱(.)⿰\1\1$/ という正規表現を使えば、同じ漢字が三つ並んだ漢字の一覧を得ることができる。 上記は簡単だが手抜きなやり方で、完全性に関してはいくつか問題がある。
文字に対する表現の曖昧性 例えば、森に対しては
⿱木林 / ⿱木⿰木木の二つの表現が考えられる。検索時にこれを考慮しなくてはならない。(同じ漢字が四つならぶ時など考えたくない…)包摂の扱い 同じ漢字なんだけど字形が違う場合、例えば「叒」の各部品はトメ、ハライの違いを考慮してデータベースに登録されており、上記のような単純な正規表現ではこれは扱う事ができない。
というわけで、今回見つけられた同じ漢字が三つの文字(ただしSnowLeopardで表示されるものに限る)は

post先のサーバがどれかの文字を正しく扱う事ができず途中で切れてしまったので画像で失礼。
参考:
ObjectSpaceダンプ
def top_objects(num=20)
ObjectSpace.each_object.inject(Hash.new{0}){|h,o|h[o.class]+=1;h}.sort_by{|k,v|-v}.first(num).each{|k,v|puts "#{k}\t#{v}"}
end
GC.start
top_objects
--
String 577159
Array 163891
Hash 93468
Time 50353
ActiveSupport::TimeWithZone 50129
ActiveModel::Errors 23365
TZInfo::TimezonePeriod 23340
ActiveSupport::HashWithIndifferentAccess 23236
RubyVM::InstructionSequence 12484
MIME::Type 1197
MatchData 1183
ActiveModel::AttributeMethods::ClassMethods::AttributeMethodMatcher::AttributeMethodMatch 1128
Class 1101
Regexp 972
Proc 704
Module 655
Gem::Version 619
…GCを生き残ったインスタンス数をダンプ。