<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8455118714591559121</id><updated>2026-04-20T17:09:44.556-05:00</updated><category term="日本語訳"/><category term="JRuby"/><category term="1.5.0"/><category term="1.5"/><category term="release"/><category term="JVM"/><category term="1.6.0"/><category term="Ant"/><category term="Maven"/><category term="Rake"/><category term="tips"/><category term="1.5.0.RC1"/><category term="1.5.0.RC2"/><category term="1.5.0.RC3"/><category term="ActiveRecord"/><category term="ActiveRecord-JDBC-Adapter"/><category term="Android"/><category term="JDBC"/><category term="Rails3"/><category term="Ruboto"/><category term="RubyGems"/><category term="RubyKaigi"/><category term="Travel"/><category term="memory"/><category term="startup"/><category term="tools"/><title type='text'>日本語JRuby</title><subtitle type='html'>JRubyに関するブログなどを出来る範囲で日本語に翻訳していきます。翻訳の際には元記事の著者からの承諾を得ています。</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-6481437610229937886</id><published>2011-07-30T00:45:00.000-05:00</published><updated>2011-07-30T00:47:38.612-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="RubyKaigi"/><category scheme="http://www.blogger.com/atom/ns#" term="Travel"/><title type='text'>JRubyKaigi 2011、RubyKaigi 2011 で喋ってきました。</title><content type='html'>&lt;h1&gt;凱旋（？）&lt;/h1&gt;&lt;p&gt;&lt;br /&gt;2011年7月14日、Rubyで飯を食うようになって初めて帰国しました。タイトルにある通り、JRuby会議とRuby会議で喋る為です。東京への出張は2004年に一回ありましたけど、その時は別の会社で、しかもその会社のCEOの通訳みたいな感じで詰まる所「おまけ」だったので、今回は少し箔がついた感じの帰国でした。&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;帰国の便&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;余談ですが、今回の帰国便はデトロイト発の羽田行きでした。ボーイング777型機で、私の座った席には電源が付いていて、ラップトップの電池の残量を気にする事なく道中を楽しむ事が出来ました。惜しむらくはWiFiがなかったのでネットで&lt;strike&gt;遊べなかった&lt;/strike&gt;調べものが出来なかった事です。乗機率がかなり酷くて、乗っていた人全員が最低三席を占拠して横になって眠れるくらいでした。東京への便が（昨今の事情で）全てそうなのかと思ったのですが、成田への便は結構混んでいたという同僚の話でした。&lt;br /&gt;&lt;/p&gt;&lt;h1&gt;JRuby会議 2011&lt;/h1&gt;&lt;p&gt;&lt;br /&gt;今回のJRuby会議は、Ruby会議の前夜祭といった雰囲気があって、50人くらいの方が参加されました。私は、トマス・エネボ氏のキーノートのスライドを翻訳して、弊社エンジンヤード社のAppCloudでJRubyを使ってRailsアプリケーションを動かす方法を紹介しました。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;AppCloudではサーバのインスタンスを立ち上げる時必要なスクリプトをS3から取ってくるのですが、私のデモの時はどういう訳かこれに失敗してちょっとあたふたしました。結局もう一つの環境を作り直して何とかデモを終えたのですが、やはりインパクトが弱くなってしまった感は否めません。会議が終わった後、S3の問題も修正できたのですが参加して下さった皆さんにそのことが伝わったかどうかは疑わしいです。非常に残念。&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;生まれて初めての地震&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;因みにJRuby会議の最中に地震がありました。会場だった青山の日本オラクルのビルは耐震構造がしっかりしていて建物全体が数秒間ユラユラしただけで事無きを得ました。地震を体験したのは実はこれが生まれて初めてでした。地震国日本に生まれたというのに。&lt;br /&gt;&lt;/p&gt;&lt;h1&gt;Ruby会議 2011&lt;/h1&gt;&lt;p&gt;&lt;br /&gt;私は「Rubyを持て、世界に出よう」という演題で話しました。周知の通り、今年でRuby会議は終わりです。私にとっては初めてのRuby会議だったのですが、私の講演は、今の日本のRubyist達が次に目指すべきあり方の一つを示す事が出来たのではないかと思います。（講演についてのもう少し詳しい話は後日書きます。）&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;初めて会う人々&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;上記の通り、Rubyを使うようになって初めての帰国だったので日本の著名なRubyistの方々多数に初めてお会いする機会に恵まれました。とは言うものの、普段からTwitterなどでやりとりをしている所為で初対面という感じがしないのが不思議といえば不思議でした。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;海の向こうにいる家族ともスカイプでほぼ毎日顔を合わせる事が出来たし、「凄い時代になったものだ」と感心しました。&lt;br /&gt;&lt;p&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/6481437610229937886/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2011/07/jrubykaigi-2011rubykaigi-2011.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/6481437610229937886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/6481437610229937886'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2011/07/jrubykaigi-2011rubykaigi-2011.html' title='JRubyKaigi 2011、RubyKaigi 2011 で喋ってきました。'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-5246323520170407646</id><published>2011-03-15T22:12:00.001-05:00</published><updated>2011-03-15T22:12:24.497-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="1.6.0"/><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="Maven"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRuby 1.6.0 がリリースされました。</title><content type='html'>&lt;href a=&quot;http://jruby.org/2011/03/15/jruby-1-6-0.html&quot;&gt;原文&lt;/a&gt;&lt;div class=&quot;body&quot;&gt;&lt;p&gt;The JRuby community is pleased to announce the release of JRuby 1.6.0.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;ホームページ: &lt;a href=&#39;http://www.jruby.org/&#39;&gt;http://www.jruby.org/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;ダウンロード: &lt;a href=&#39;http://www.jruby.org/download&#39;&gt;http://www.jruby.org/download&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;JRuby 1.6.0 が正規にリリースされました。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;JRuby 1.6.0 は過去最大のJRubyリリースです。&lt;br /&gt;このリリースは、ユーザから報告のあった数百の不具合を直し、またRuby 1.9.2との高い互換性を実現しています。&lt;br /&gt;またウィンドウズ上で継続的インテグレーションを行い、これをサポートするプラットフォームに加えました。&lt;br /&gt;ウィンドウズでRubyを体験するのにJRuby 1.6は最適の方法と言えるでしょう。&lt;br /&gt;このリリースではRubyのAPIに基づいたC拡張への対応を試験的に取り入れています。&lt;br /&gt;更に、今までの主なリリースと同様、ユーザの声に耳を傾け、安定性とパフォーマンスの向上を実現しています。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;今後一二ヶ月の間は1.6.0へのフィードバックを受けて1.6.1, 1.6.2等、細かくリリースを行う予定です。&lt;br /&gt;1.6.0を是非使ってみて、報告をして下さい。&lt;br /&gt;&lt;/p&gt;&lt;h3 id=&#39;major_features&#39;&gt;主な特長&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Ruby 1.9.2言語とAPI互換性の実現&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Encoding::Converterとripperは未対応&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Rubyメソッド呼び出しのパフォーマンス向上&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;組み込みのプロファイラ(&amp;#8211;profile, &amp;#8211;profile.graph)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;RSpecを配布ファイルから外しました&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;C拡張のサポート（試験的）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;MavenアーティファクトをRuby gemとして扱える（プレビュー）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Windowsプラットフォームへの対応&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;1.9標準ライブラリをjruby-complete.jarに追加&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;組み込みAPIの更なる改善&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;2000のコミットと270を超える不具合の解消&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt; &lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/5246323520170407646/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2011/03/jruby-160.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/5246323520170407646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/5246323520170407646'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2011/03/jruby-160.html' title='JRuby 1.6.0 がリリースされました。'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-6595633956095503556</id><published>2010-12-30T10:54:00.001-06:00</published><updated>2010-12-30T11:21:19.363-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRubyの一年を振り返って</title><content type='html'>&lt;a href=&quot;http://www.engineyard.com/blog/2010/jruby-2010-year-in-review/&quot;&gt;原文&lt;/a&gt;: チャールズ＝オリバー＝ナター&lt;br /&gt;&lt;br /&gt;皆さん、こんにちは。&lt;br /&gt;&lt;br /&gt;2010年ももうすぐ終わり。この一年を振り返ってJRubyにとって重要な出来事や人々を見て行きましょう。&lt;br /&gt;2010年は、JRubyにとって素晴らしい年でした。様々なプロジェクトに採用され、また、第一級のRuby言語実装としても第一級のJVM言語としても人々に認知され、更にはJRuby自体も多いに進化した一年でした。早速みていきましょう。&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;h2&gt;JRubyを巡る人々&lt;/h2&gt;&lt;br /&gt;JRubyの大事な使命の一つは、より多くの人にRubyというプログラム言語を届ける事です。&lt;br /&gt;その為に、世界中を飛び回ったり、ブログ記事を書いたり、援助者を募り、パッチを取り込んだり、ユーザのサポートに努めてきました。2010年特に貢献のあった方々を挙げて行きましょう。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a href=&quot;http://twitter.com/#!/hiro_asari&quot;&gt;浅里洋嗣氏&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;浅里氏は2009年を通じて貢献の実績があり、&lt;a href=&quot;http://wiki.jruby.org/MailingLists&quot;&gt;メーリングリスト&lt;/a&gt;や&lt;a href=&quot;http://wiki.jruby.org/IRC&quot;&gt;IRCチャンネル&lt;/a&gt;でも、JRubyを使ったアプリケーションを動かす際に起こる様々な問題点を解決する手助けをする常連でした。&lt;br /&gt;2010年初頭にEngine Yard社がJRubyサポートエンジニアの募集を行ったとき、浅里氏はこの仕事に適任だったと言えます。&lt;br /&gt;彼はフルタイムで雇用され、JRubyコミッタに迎え入れられました。&lt;br /&gt;今年の終わりにはカンファレンスなどでも講演をする事にもなりました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a href=&quot;http://twitter.com/#!/nahi&quot;&gt;Nahi（中村浩士）氏&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;NahiさんはRuby（CRuby、つまりMRI）のコアチームのメンバーとして、OpenSSLに代表される暗号、I/O等、システムレベルを専門に貢献されてきました。&lt;br /&gt;Rubyの標準ライブラリを覗いてみると、彼の名前が其処彼処に見えるでしょう。&lt;br /&gt;2010年の半ば頃、NahiさんはJRubyでopensslライブラリを使う為の&lt;a href=&quot;https://github.com/jruby/jruby-ossl&quot;&gt;jruby-openssl&lt;/a&gt;の手伝いを買って出てくれました。&lt;br /&gt;Nahiさんは&lt;a href=&quot;http://twitter.com/#!/olabini&quot;&gt;Ola Bini氏&lt;/a&gt;のOpenSSLの移植という大作を基に、CRubyバージョンとほぼ100％互換性のあるライブラリを造り上げてくれました。 opensslが如何に低水準の事を取り扱うのかを考えてみると、これは正に驚くべき偉業です。&lt;br /&gt;この後、Nahiさんは他の厄介なサブシステムの手伝いをされ、またJRubyの大きな支援者として活躍されています。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a href=&quot;http://twitter.com/#!/calavera&quot;&gt;David Calavera氏&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;Calavera氏もまた2009年以来の貢献者で、2010年も引き続き多くの貢献をしてくれました。&lt;br /&gt;彼の貢献の多くはRuby 1.9仕様の充実や、ユーザから報告のあった不具合の修正、そしてメーリングリストとIRCでのユーザサポートです。&lt;br /&gt;加えてDavidは素晴らしい&lt;a href=&quot;https://github.com/calavera/trinidad&quot;&gt;Trinidad&lt;/a&gt; gem（&lt;a href=&quot;http://tomcat.apache.org/&quot;&gt;Tomcat&lt;/a&gt;を組み込んだ、JRubyによるRails/Rackアプリケーションコンテナサーバ）を書きました。Trinidadは急速に世界中のJRubyユーザの間に浸透しています。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a href=&quot;http://twitter.com/#!/objo&quot;&gt;Joe O&#39;Brien氏&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;O&#39;Brien氏はオハイオ州に本社を置くRubyとRailsのコンサルタンティング会社&lt;a href=&quot;http://edgecase.com/&quot;&gt;EdgeCase&lt;/a&gt;の創始者の一人です。&lt;br /&gt;大企業関係のプロジェクトに経験が多く、大企業の新しいテクノロジーを取り入れる傾向の薄さを知るO&#39;Brien氏はJRubyの偉大な支持者の一人です。&lt;br /&gt;2010年、O&#39;Brien氏は彼自身のプロジェクトである&quot;eRubyConf&quot;を一年休んで、始めての単体開催となる&lt;a href=&quot;http://jrubyconf.com/&quot;&gt;JRubyConf&lt;/a&gt;の実施を現実のものとする手伝いをして下さいました。&lt;br /&gt;このような機会に恵まれてJRubyをより多くの人に知ってもらう事が出来るのはとても素晴らしい事です。&lt;br /&gt;O&#39;Brien氏のお陰でJRubyConfが実に素晴らしいイベントであった事は言うまでもありません。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a href=&quot;http://www.engineyard.com/&quot;&gt;Engine Yard社&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;Engine Yard社の絶え間ないJRubyへのサポートにも感謝致します。&lt;br /&gt;Engine Yard社はJRubyのコアメンバー（筆者、Tom Enebo氏、Nick Sieger氏、浅里氏）の新しい「家」となり、またマーケティング、トラベル、技術的そして精神的な面からも支えて頂いています。&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.engineyard.com/services/jruby&quot;&gt;JRubyのサポートとプロフェッショナルサービス&lt;/a&gt;は今年開始されました。&lt;br /&gt;&lt;a href=&quot;http://www.engineyard.com/products/xcloud&quot;&gt;xCloud&lt;/a&gt;ではJRubyは既にサポートされていますし、&lt;br /&gt;&lt;a href=&quot;http://www.engineyard.com/products/appcloud&quot;&gt;AppCloud&lt;/a&gt;でも&lt;a href=&quot;http://docs.engineyard.com/beta/home&quot;&gt;ベータプログラム&lt;/a&gt;によりJRubyを試用することが可能です。&lt;br /&gt;Engine Yard社で働く事は素晴らしく、会社の収益に貢献出来るのは尚の事素晴らしいです。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;ユーザと貢献者の皆さん&lt;/h3&gt;&lt;br /&gt;勿論、ユーザと貢献者無しにJRubyを語る事は出来ません。&lt;br /&gt;今年に入ってJRubyを使っているというサイトの報告を何十も貰いましたし、Ruby gemの作者達もJRubyを意識してテストやサポートを始めました。&lt;br /&gt;Rails作者であるDavid Heinemeier Hansson氏によれば、&lt;a href=&quot;http://weblog.rubyonrails.org/2010/8/29/rails-3-0-it-s-done&quot;&gt;Rails 3.0は（C Rubyに加えて）JRubyでも動くように設計されています&lt;/a&gt;。&lt;br /&gt;Twitterにおいても毎日&lt;a href=&quot;http://search.twitter.com/search?q=jruby&quot;&gt;JRubyについてのツイートが何百もあり&lt;/a&gt;、&lt;a href=&quot;http://wiki.jruby.org/MailingLists&quot;&gt;JRubyに関するメーリングリスト&lt;/a&gt;も今年に入って14000件の投稿があり、何十もの世界中のカンファレンスを通じて、何千というユーザや将来のユーザたり得る人々に出会う事が出来ました。&lt;br /&gt;2010年をJRubyにとって最高の年にして下さったユーザ、貢献者、そしてRubyライブラリとアプリケーションの作者の皆さんに感謝の意を表します。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;JRubyの進化&lt;/h2&gt;&lt;br /&gt;勿論JRuby自体にも多くの動きがありました。&lt;br /&gt;今年に入っての&lt;a href=&quot;https://github.com/jruby&quot;&gt;コミットの数は（マスターブランチで）2300を超え&lt;/a&gt;、&lt;a href=&quot;http://jira.codehaus.org/secure/IssueNavigator.jspa?reset=true&amp;amp;jqlQuery=project+%3D+JRUBY+AND+status+in+%28Resolved%2C+Closed%29+AND+created+%3E%3D+-360d+AND+resolved+%3E%3D+-360d+ORDER+BY+created+ASC%2C+priority+DESC&quot;&gt;567に上るバグレポートを解決し&lt;/a&gt;（とは言うものの、更に&lt;a href=&quot;http://jira.codehaus.org/secure/IssueNavigator.jspa?reset=true&amp;amp;jqlQuery=project+%3D+JRUBY+AND+created+%3E%3D+-360d+ORDER+BY+created+ASC%2C+priority+DESC&quot;&gt;868件&lt;/a&gt;の追加がありましたので我々の仕事はまだまだ続きます）、八つ（1.4.1, 1.5.0-1.5.6）の&lt;a href=&quot;http://jruby.org/download&quot;&gt;JRubyリリース&lt;/a&gt;を行い、 &quot;&lt;a href=&quot;http://www.rubyspec.org/&quot;&gt;RubySpec&lt;/a&gt;&quot;のテスト結果を 1.8互換モードで99%、1.9互換モードで90%を越えるまでに改善しました。&lt;br /&gt;2011年初めに予定されているJRuby 1.6のリリースで公式な発表となります。&lt;br /&gt;主立った改善点を見ていきましょう。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Ruby 1.9との互換&lt;/h3&gt;&lt;br /&gt;今年八月の&lt;a href=&quot;http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/47321&quot;&gt;Ruby 1.9.2&lt;/a&gt;リリースを受けて、JRubyでもこの1.9系統のRubyとの互換性を最優先事項にしました。&lt;a href=&quot;http://pl.linkedin.com/pub/marcin-miel%C5%BCy%C5%84ski/1/975/77&quot;&gt;Marcin Mielzynski氏&lt;/a&gt;、Ola Bini氏、David Calavera氏、そして浅里氏らの貢献により断片的なサポートの素地は既に在りましたが、本格的な作業はRubyのコアチームが最終的な1.9.2をリリースするまでは保留にしておきました。&lt;br /&gt;夏の1.9.2リリースから、何百ものコミットがあり、また多数の不具合を修正しました。その結果JRubyは1.9互換モードでRubySpecの90%、そしてRailsの一部である&lt;a href=&quot;http://as.rubyonrails.org/&quot;&gt;ActiveSupport&lt;/a&gt;のテストの95%をパスするまでになりました。&lt;br /&gt;JRubyはこの先数ヶ月で正式に1.9互換となる見込みです。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Windowsのサポート&lt;/h3&gt;&lt;br /&gt;私達はJRubyが「どこにでもRuby」を実現する最善の手段であると信じています。&lt;br /&gt;このために2010年にはWindows上でJRubyをより良く動かす為の手段を講じてきました。&lt;br /&gt;様々なJVMについて言える事ですが、JRubyのコアである仮想マシンは既に堅牢なものです。&lt;br /&gt;ところがRubyの機能という物はシステムレベルでの機能を含んでおり、あらゆるOSプラットフォームでのサポートを一様に実現するのは難しいものがあります。&lt;br /&gt;機能を苦労して実装しても、RubyプログラマはWindowsではどうしても動かなかったりビルド出来ないC拡張に出くわす事がしばしばあります。&lt;br /&gt;最新のRubyのビルドを手にする事すらままならない可能性もあります。&lt;br /&gt;私達は、鍵となるC拡張をJava（またはRubyとJavaの統合）に移植する事によってWindowsを使う人たちが初めの一歩を踏み出しやすくする為の努力を続けています。&lt;br /&gt;そしてJRubyはWindowsでRubyを使う最も簡単な方法と考えられる事もあります。&lt;br /&gt;2011年もこの方面での作業は続きます。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Rails 3のテスト&lt;/h3&gt;&lt;br /&gt;JRubyはCRuby以外のRuby言語実装の中では（&lt;a href=&quot;http://blog.headius.com/2006/05/and-they-said-jruby-was-dead.html&quot;&gt;2006年以来&lt;/a&gt;）最も長く「&lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt;を走らせて」いますが、この間Rails自体のテストを100%通す事は実は出来ていませんでした。&lt;br /&gt;2010年、浅里氏、Calavera氏、&lt;a href=&quot;http://twitter.com/#!/nicksieger&quot;&gt;Nick Sieger&lt;/a&gt;氏、&lt;a href=&quot;http://twitter.com/#!/tom_enebo&quot;&gt;Tom Enebo&lt;/a&gt;氏らの貢献により事態は一変し、JRubyはRailsのテストを100%通すようになりました。&lt;br /&gt;更に素晴らしいのは、JRubyは多くのRuby言語実装のうち、&lt;a href=&quot;http://ci.jruby.org/job/rails-3-0-stable/&quot;&gt;継続的インテグレーションをRailsに対して毎日行っている&lt;/a&gt;唯一のものであるという点です。&lt;br /&gt;RailsをJRubyで動かそうとするユーザが快適な環境を提供する努力を我々は怠りません。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;C拡張のサポート&lt;/h3&gt;&lt;br /&gt;2010年の&lt;a href=&quot;http://rubysoc.org/&quot;&gt;Ruby Summer of Code&lt;/a&gt;のプロジェクトの一つとして、&lt;a href=&quot;http://twitter.com/#!/wmeissner&quot;&gt;Wayne Meissner&lt;/a&gt;氏が造り上げたプロトタイプを基に&lt;a href=&quot;http://twitter.com/#!/timfelgentreff&quot;&gt;Tim Felgentreff&lt;/a&gt;氏は&lt;a href=&quot;http://blog.headius.com/2010/07/what-jruby-c-extension-support-means-to.html&quot;&gt;JRubyにおけるC拡張のサポート&lt;/a&gt;を実現しました。&lt;br /&gt;予想を遙かに超えた、実に素晴らしい努力の賜物で、（私は絶対に不可能だと考えていたのですが、Felgentreff氏とMeissner氏は私が間違っていた事を証明してくれました）よく見かける多くのC拡張は「一通り動く」ようになりました。&lt;br /&gt;勿論、（多くのOSプラットフォームで、安定して、また並行して動かすという観点から）Javaでそれに相当する物や移植した物があればそちらを薦める事に変わりはありませんが、JRubyへの移行を楽にする短期的な手段としては問題ないでしょう。&lt;br /&gt;これも近いうちにリリースされるでしょう。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;性能&lt;/h3&gt;&lt;br /&gt;言語実装としてのJRubyも見えない所で進化しています。&lt;br /&gt;&lt;a href=&quot;https://github.com/jruby/jruby/commits/master?author=subbuss&quot;&gt;Subbu Sastry&lt;/a&gt;氏とEnebo氏は、新しいIR（中間表現）と、それを利用してRubyコードを最適化するコンパイラの実装を進めていて、既におおよその形が出来上がっています。2011年にはこれを基にしてJRubyのパフォーマンスの更なる向上が期待出来そうです。&lt;br /&gt;私もJRubyの動的最適化に努めています。インタープリタをプロファイリングする事で動的な呼び出しを取り除いたり、Rubyメソッドの呼び出し毎に起こるオーバーヘッドを取り除いたり、といった具合です。&lt;br /&gt;&lt;a href=&quot;http://blog.headius.com/2010/05/kicking-jruby-performance-up-notch.html&quot;&gt;暫定的なテスト&lt;/a&gt;によると、この「dynopts」オプションを使うとJavaそのもののパフォーマンスに匹敵するような結果を得る事も可能である事が分ります。同時に、（Ruby言語実装の中にあって&lt;a href=&quot;http://programmingzen.com/2010/07/19/the-great-ruby-shootout-july-2010/&quot;&gt;既に最善のものの一つである&lt;/a&gt;とは言え）JRubyのパフォーマンスがこれ以上ないくらい最適化されているのではないということを実感する一瞬でもあります。&lt;br /&gt;2011年初頭にはこの方面での作業が続きます。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;周辺のソフトウェア&lt;/h2&gt;&lt;br /&gt;JRubyのコアチームがJRubyの改善に努力する一方、多くの方々がJRubyに関わるライブラリ、サーバなどを進化させています。&lt;br /&gt;これらのうち幾つかを見ていきましょう。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;win32ole&lt;/h3&gt;&lt;br /&gt;JRubyのバグトラッカーで解決されずにいた物のうちで最も古い物の一つが「win32ole」ライブラリの問題でした。&lt;br /&gt;win32oleライブラリは、Windows上でOLEへのクリーンなアクセスを可能にします。&lt;br /&gt;これにより、ネーティブのコードを書かずにマイクロソフトOfficeやインターネットエクスプローラ、その他のWindows固有のアプリケーションやライブラリを呼び出すことが出来るようになります。&lt;br /&gt;これはEngine Yard社のAudentes Technology社とのプロフェッショナルサービス契約の一環として行われました。&lt;br /&gt;JavaとCOMのブリッジであるJacobライブラリを&lt;a href=&quot;https://github.com/enebo/racob&quot;&gt;大幅に改善し、それをガッチリ統合して&lt;/a&gt;、&lt;a href=&quot;https://github.com/enebo/jruby-win32ole&quot;&gt;win32oleサポート&lt;/a&gt;を実現しました。&lt;br /&gt;Enebo氏の数週間に渡る並々ならぬ努力の結果、Rubyで使うwin32oleライブラリとしては最も堅牢でマルチスレッドで利用できるものが生まれました。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;ActiveRecord JDBC&lt;/h3&gt;&lt;br /&gt;Rails 3.0をサポートする為には、JRuby自体の修正に加えてデータベース接続の為のアダプターも数々のデータベースのいずれにおいてもテストを100%パスする物である必要がありました。&lt;br /&gt;「&lt;a href=&quot;https://github.com/nicksieger/activerecord-jdbc-adapter&quot;&gt;ActiveRecord-JDBC&lt;/a&gt;」の強力な推進者であるSieger氏は、&lt;a href=&quot;http://blog.nicksieger.com/articles/tag/jdbc&quot;&gt;AR-JDBC 1.0を今年リリースして&lt;/a&gt;それを実現しました。&lt;br /&gt;この仕事は続いており、Javaで書かれたデータベースである&lt;a href=&quot;http://db.apache.org/derby/&quot;&gt;Derby&lt;/a&gt;（&lt;a href=&quot;http://www.oracle.com/technetwork/java/javadb/overview/index.html&quot;&gt;JavaDB&lt;/a&gt;）、&lt;a href=&quot;http://hsqldb.org/&quot;&gt;Hypersonic SQL&lt;/a&gt;、&lt;a href=&quot;http://www.h2database.com/html/main.html&quot;&gt;H2&lt;/a&gt;をもサポートしています。&lt;br /&gt;これによりJRubyは、多種多様なプラットフォームでRailsアプリケーションを動かすのに最も手軽な手段になったと言えるでしょう。&lt;br /&gt;JRubyのユーザの中には実に変わったデータベースとOS環境の人々が居るのがその証左です。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;デプロイメントのオプション&lt;/h3&gt;&lt;br /&gt;以下に挙げる方々の貢献でJRubyでサーバアプリケーションを書くのが一層簡単になりました。&lt;br /&gt;&lt;br /&gt;Nick Sieger氏はwarblerとjruby-rackライブラリのバージョン1.0を今年リリースしました。&lt;br /&gt;&lt;a href=&quot;https://github.com/nicksieger/warbler&quot;&gt;Warbler&lt;/a&gt;により、Rackに準拠したアプリケーション（Railsを含む）をWAR（Web ARchive）ファイルとしてJavaウェブコンテナにデプロイ出来ます。&lt;br /&gt;WinStoneというサーバの搭載により、実行可能なウェブサーバをWarblerだけで造り上げることも可能になりました。&lt;br /&gt;さらにSieger氏は、&quot;warble&quot;コマンドだけで、Rubyのアプリケーションを1つの実行可能JAR形式にまとめられるようにしてくれました。凄いです。&lt;br /&gt;Railsを大企業向けに浸透させる事が出来る可能性を持ったデプロイメントの選択肢はWarberを置いて他にありません。&lt;br /&gt;その意味でバージョン1.0は記念すべきマイルストーンです。&lt;br /&gt;Warblerと表裏一体を成すjruby-rackは、rack仕様のインターフェイスとJava servlet APIの互換を実現し、servletに拠ったRubyアプリケーションの中核を成す物です。&lt;br /&gt;&lt;br /&gt;コマンドラインを使う人々には&lt;a href=&quot;https://github.com/calavera/trinidad&quot;&gt;Trindad&lt;/a&gt;もデビューしました。David Calavera氏はjruby-rackを使ってTomcatを組み込んだツールを作りました。これによりJRubyユーザは高速で並行処理に長けたサーバをたったの7MBのgemで手にする事が出来るようになりました。&lt;br /&gt;これと似た物として、浅里氏がメンテナを務める&lt;a href=&quot;https://github.com/jruby/glassfish-gem&quot;&gt;GlassFish gem&lt;/a&gt;が挙げられます。&lt;br /&gt;TomcatのかわりにOracleの&lt;a href=&quot;http://glassfish.java.net/&quot;&gt;GlassFish&lt;/a&gt;サーバの中心を成す&lt;a href=&quot;http://grizzly.java.net/&quot;&gt;Grizzly&lt;/a&gt;を組み込んでいます。&lt;br /&gt;この二つのgemは紛れもなくRailsのアプリケーションを世に出す最も簡単な方法と言えます。&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.jboss.org/&quot;&gt;JBoss&lt;/a&gt;を好む向きには、&lt;a href=&quot;http://twitter.com/#!/bobmcwhirter&quot;&gt;Bob McWhirter&lt;/a&gt;氏とRedHatの彼のチームにより産み出された&lt;a href=&quot;http://torquebox.org/&quot;&gt;TorqueBox&lt;/a&gt;があります。&lt;br /&gt;これにはJavaのアプリケーションサーバの中で最も素晴らしいJRubyが実現されています。&lt;br /&gt;TorqueBoxはjruby-rackによってJRubyアプリケーションをデプロイしていますが、それに加えてJava EEサブシステムの為のRubyで書かれたAPIやプラグイン、バッチ処理、ウェブサービス、その他諸々を提供しています。&lt;br /&gt;「Java EEの為のRuby」として最善のオプションと言えます。&lt;br /&gt;既にJBossやJava EEを使っていてRubyを弄ってみたいと言う人（またそうでなくとも色々なサービスが初めから備わっている方が良いという人）にはこれをお勧めします。&lt;br /&gt;&lt;br /&gt;最後に&lt;a href=&quot;http://twitter.com/#!/johnwoodell&quot;&gt;John Woodell&lt;/a&gt;氏と&lt;a href=&quot;http://twitter.com/#!/ribrdb&quot;&gt;Ryan Brown&lt;/a&gt;氏が続けている&lt;a href=&quot;http://code.google.com/appengine/&quot;&gt;Google AppEngine&lt;/a&gt; for JavaにおけるJRubyサポートが挙げられます。&lt;br /&gt;GAE/Jは小さなサービスを手軽に実現出来るツールで、JRubyで書かれたアプリケーションを動かす場所として成果を挙げています。&lt;br /&gt;両氏は&lt;a href=&quot;http://code.google.com/p/appengine-jruby/wiki/GettingStarted&quot;&gt;JRuby-on-GAE&lt;/a&gt;を通じてJRubyユーザをサポートしており、JRubyユーザはデプロイメント手段の選択の幅が広がる事を歓迎しています。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;開発ツールと管理ツール&lt;/h3&gt;&lt;br /&gt;JRubyでは&lt;a href=&quot;http://download.oracle.com/javase/6/docs/technotes/tools/share/jvisualvm.html&quot;&gt;標準のJVM/JDKツール&lt;/a&gt;と&lt;a href=&quot;http://download.oracle.com/javase/1.5.0/docs/api/javax/management/package-summary.html&quot;&gt;管理インターフェイス&lt;/a&gt;を使う事が出来ますが、このようなツールはRubyを普段使うプログラマにとっては馴染みが薄く、時に仰々しい物です。&lt;br /&gt;このため、「--profile」というフラグでRubyコードだけを考慮する計測化プロファイラーを動かす事が出来ます。（コールグラフのサポートも近く追加される見込みです。）&lt;br /&gt;&lt;a href=&quot;http://rubyforge.org/projects/ruby-debug/&quot;&gt;ruby-debug&lt;/a&gt; gemのメンテナ諸氏との連携によりJRubyをバックエンドとするデバッガが正式にリリースされ、&lt;a href=&quot;http://blog.headius.com/2010/12/jruby-finally-installs-ruby-debug-gem.html&quot;&gt;ruby-debug gemは綺麗にインストールされるようになりました。&lt;/a&gt;&lt;br /&gt;RubyGemsにも起動時間短縮の為のパッチを&lt;a href=&quot;http://blog.headius.com/2010/12/improved-jruby-startup-by-deferring-gem.html&quot;&gt;提供しました&lt;/a&gt;し、JRubyが使うスクリプトも（&lt;a href=&quot;https://github.com/mkristian&quot;&gt;mkristian&lt;/a&gt;氏の多大なる協力の元）修正してmavenライブラリをRuby gemとしてインストールしたり依存の解消を行ったり出来るようになりました。&lt;br /&gt;&lt;a href=&quot;http://jruby-ja.blogspot.com/2010/02/rakeant.html&quot;&gt;AntとRakeの双方向統合&lt;/a&gt;も今年リリースされました。&lt;br /&gt;これによりAntで書かれたビルドスクリプトをRakefileで書き換えたり二つをシームレスに組み合わせる事が至極簡単になりました。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Java純正のNokogiri&lt;/h3&gt;&lt;br /&gt;2009年頃、RubyでXMLを扱うライブラリの定番として&lt;a href=&quot;http://nokogiri.org/&quot;&gt;Nokogiri&lt;/a&gt;が定着し始めました。&lt;br /&gt;クリーンで高速なこのライブラリは人気のあるlibxmlライブラリを使っています。&lt;br /&gt;JRubyユーザもこのライブラリの恩恵にあやかる事が出来ましたが、それは速度にC拡張に劣るFFIを使った物を使わざるを得ませんでした。&lt;br /&gt;Ruby Summer of Codeのプロジェクトの一つとして&lt;a href=&quot;http://twitter.com/#!/serabe&quot;&gt;Sergio Arbeo氏&lt;/a&gt;はJavaのライブラリである&lt;a href=&quot;http://xerces.apache.org/&quot;&gt;Xerces&lt;/a&gt;を使って純正Javaのライブラリを作り始めました。&lt;br /&gt;完了にはまだ沢山の課題が残っているうちに、残念ながら夏は終わってしまいましたが、&lt;a href=&quot;http://twitter.com/#!/yokolet&quot;&gt;原田洋子氏&lt;/a&gt;（組み込みJRuby、JSR-223及びBSFの実装者）がこの後を引き継いでくれました。&lt;br /&gt;この結果、どのプラットフォームでもlibxmlの有無に関わらずネーティブのコードを書く事無しにほぼ完璧に動くNokogiriが完成しました。&lt;br /&gt;これは最もポータブルなNokogiriであると言うだけでなく、FFIバージョンに較べてかなり高速な物です。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;JRubyを取り巻くコミュニティ&lt;/h2&gt;&lt;br /&gt;前にも述べましたが、JRubyを使ってくれるユーザ、イベント、そしてプロジェクトなしにはJRubyはJRubyたり得ません。&lt;br /&gt;JRubyのコミュニティではどんな事が起こったのかを振り返ってみます。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a href=&quot;http://jrubyconf.com/&quot;&gt;JRubyConf 2010&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;Joe O&#39;Brien氏とEngine Yard社の協力により、始めての単体開催となるJRubyConfがありました。10月の初めに150人を超す参加者が世界中からオハイオ州コロンバスに集い、JRuby、JRuby on Rails、JRuby on Android、JRuby関連のプロジェクト、その他（勿論JRubyに特化されていない議題もありました）についての講演に耳を傾けました。&lt;br /&gt;昨年RubyConf 2009直後に開催された&lt;a href=&quot;http://blog.headius.com/2009/09/announcing-jrubyconf-2009.html&quot;&gt;JRubyConf 2009&lt;/a&gt;と今年のJRubyConf 2010の成功を受けて、来年も是非JRubyConf 2011を開催したい所です。ヨーロッパでもJRubyConfを、という気運もあります。あなたの参加をお待ちしています。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;ブログ&lt;/h3&gt;&lt;br /&gt;JRubyのコミュニティの面々は何百と言う記事を今年書きました。多すぎてここでは挙げません。いずれ纏めて発表出来ればいいと思いますが、それまではどうか独自に検索して下さい。JRubyが実に目新しい方法で使用されているのが解ると思います。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;会議とユーザグループ&lt;/h3&gt;&lt;br /&gt;RubyとJavaの両方に根差すJRubyは両方のイベントに気を配る必要があります。&lt;br /&gt;そしてJRubyの普及の為、色んな場所へと旅をしました。&lt;br /&gt;今では世界中でRubyやJavaの会議と言えば誰かがJRubyについて話をしてしているでしょうし、RubyやJavaのユーザグループでは最低一回JRubyについての発表があったのではないでしょうか。&lt;br /&gt;JRubyのコアチームメンバーがした物が多いですが、実際にJRubyを使っているユーザによる発表も数多くあり、JRubyの普及に一役かっています。&lt;br /&gt;JRubyコミュニティは益々多くのイベントに姿を現していますし、この傾向は2011年も続くよう期待しています。&lt;br /&gt;&lt;br /&gt;2010年にはJRubyを中心に据えたユーザグループが誕生しました。&lt;a href=&quot;http://twitter.com/#!/jruby_users_jp&quot;&gt;JRuby Users JP&lt;/a&gt;です。片手に余る回数の会合を既に開催しており、Ruby会議2010ではメンバーの方々ともお会いする事が出来ました。&lt;br /&gt;&lt;br /&gt;さあ、あなたもJRubyについて発表されては如何ですか？&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;RubyConf 2010でのJRubyトラック&lt;/h3&gt;&lt;br /&gt;筆者自身による初めてのJRubyについての（実は人前で喋る最初の）発表は&lt;a href=&quot;http://www.zenspider.com/Languages/Ruby/RubyConf2005.html&quot;&gt;RubyConf 2005&lt;/a&gt;でした。当時JRubyはIRBを動かす事もままならず、他の講演者達はJRubyをネタにしてジョークを飛ばしていました。&lt;br /&gt;それが2010年になると、&lt;a href=&quot;http://www.rubyconf.org/schedule&quot;&gt;JRubyを主な題材とする講演は数多くあり&lt;/a&gt;、その他の講演でも取り上げられる事がしばしばになりました。&lt;br /&gt;RubyConf主催者の方々に感謝します。そして、JRubyを受け入れてくれたRubyのコミュニティの人々に敬意を表します。&lt;br /&gt;我々の努力が、諸氏がより良いRubyプログラマとなる一助となっている事を実感しています。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;LinkedIn社の&quot;Signal&quot;&lt;/h3&gt;&lt;a href=&quot;http://www.linkedin.com/&quot;&gt;LinkedIn&lt;/a&gt;社は多くのプログラミング言語を用いて開発をする事で知られている所で、JRubyをユーザ向けに使った（&lt;a href=&quot;http://www.linkedin.com/opensocialInstallation/preview?_ch_panel_id=1&amp;amp;_applicationId=1900&quot;&gt;LinkedIn Polls&lt;/a&gt;）先駆者の一つです。&lt;br /&gt;LinkedIn社は今年、野心的な、&lt;a href=&quot;http://blog.linkedin.com/2010/09/29/linkedin-signal/&quot;&gt;Signal&lt;/a&gt;というソーシャルアグリゲータをユーザのプロファイルへとつなげるアプリケーションを発表しました。&lt;br /&gt;そのフロントエンドは&lt;a href=&quot;http://www.infoq.com/articles/linkedin-scala-jruby-voldemort&quot;&gt;JRuby&lt;/a&gt;で、Scala等、他のJVM言語によりバックエンドサービスが実装されています。&lt;br /&gt;このプロジェクトの成功により、これに似たプロジェクトの幾つかにゴーサインが出ているそうです。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;RedCar&lt;/h3&gt;&lt;br /&gt;Macユーザなら、エディタは&lt;a href=&quot;http://macromates.com/&quot;&gt;TextMate&lt;/a&gt;を使っているのではないでしょうか。&lt;br /&gt;大人気のこのエディタに触発されて&lt;a href=&quot;http://twitter.com/#!/danlucraft&quot;&gt;Dan Lucraft氏&lt;/a&gt;は&lt;a href=&quot;http://redcareditor.com/&quot;&gt;RedCar&lt;/a&gt;を書きました。&lt;br /&gt;そして手軽に弄る事が出来るよう、Lucraft氏はRedCarをRubyで書いたのです。&lt;br /&gt;2009年の終わり頃、Lucraft氏はマルチプラットフォームでのサポートを容易にするため、コードベースをC RubyとGTKで書かれた物から&lt;a href=&quot;http://redcareditor.com/blog/2009/08/redcar-is-moving-to-jruby/&quot;&gt;JRubyへと移植する&lt;/a&gt;決断をしました。 &lt;br /&gt;2010年、RedCarは幾つかのリリースを経て、沢山のフィーチャを備え、多くのユーザと貢献者を獲得しました。&lt;br /&gt;かく言う私もTextMateからRedCarに乗り換えたユーザの一人です。&lt;br /&gt;JRubyについての講演でRedCarを使うのは実に快いです。&lt;br /&gt;そしてJRubyで書かれたデスクトップのアプリケーションに人気が出るのもとても良い事です。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;a href=&quot;http://ruboto.org/&quot;&gt;Ruboto&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;2010年はAndroidプラットフォームの人気が爆発した年でもありました。&lt;br /&gt;AndroidはJavaに似たシステムですので、Javaの行く所にはJRubyもついて行きます。&lt;br /&gt;2009年に私が実験的に行った&lt;a href=&quot;http://blog.headius.com/2009/02/ruboto-is-your-friend.html&quot;&gt;JRubyをAndroidに移植する&lt;/a&gt;試みを&lt;br /&gt;&lt;a href=&quot;http://twitter.com/#!/jberkel&quot;&gt;Jan Berkel氏&lt;/a&gt;や&lt;a href=&quot;https://github.com/rscottm&quot;&gt;Scott Moyer氏&lt;/a&gt;等が&lt;a href=&quot;https://github.com/ruboto/ruboto-irb&quot;&gt;Ruboto IRB&lt;/a&gt;に大幅に手を加え、今年&lt;a href=&quot;http://www.appbrain.com/app/ruboto-irb-(ruby-on-android)/org.ruboto.irb&quot;&gt;Androidマーケットプレイスにリリースされました&lt;/a&gt;。&lt;br /&gt;Ruby Summer of Codeの参加者である&lt;a href=&quot;http://twitter.com/#!/jackowayed&quot;&gt;Daniel Jackoway氏&lt;/a&gt;は&lt;a href=&quot;https://github.com/ruboto/ruboto-core&quot;&gt;Ruboto Core&lt;/a&gt;プロジェクトを起こし、Androidで動くJRubyベースのアプリケーションの生成器とそれにまつわるAPIを作り上げました。&lt;br /&gt;また&lt;a href=&quot;http://twitter.com/#!/jaymcgavren&quot;&gt;Jay McGavren氏&lt;/a&gt;等はRubotoでの実験を多いに宣伝して、Rubyのモバイルの分野での可能性を示してくれています。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;「Using JRuby」刊行&lt;/h3&gt;&lt;br /&gt;5人の執筆者（コアチームからの四人—私、Sieger氏、Enebo氏、Bini氏と&lt;a href=&quot;http://twitter.com/#!/undees&quot;&gt;Ian Dees&lt;/a&gt;氏）による二年の歳月を経て、JRuby本の決定版とも言うべき「&lt;a href=&quot;http://pragprog.com/titles/jruby/using-jruby&quot;&gt;Using JRuby&lt;/a&gt;」が遂に完成しました。&lt;br /&gt;この記事を書いている現在、本は版組みに入っており、2011年一月に出荷の予定になっています。&lt;br /&gt;これには&lt;a href=&quot;http://pragprog.com/&quot;&gt;Pragmatic Programmers&lt;/a&gt;からの根気強い支持が欠かせませんでした。&lt;br /&gt;それを主題とするカンファレンスと、そしてそれを主題とする本が出版されたと言うことは、私にとってみれば、そのプロジェクトが一人前になったと言う事です。&lt;br /&gt;JRubyにも遂にその日がやって来ました。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Bossie&lt;/h3&gt;&lt;br /&gt;JRubyは他の分野でも認められるに至りました。&lt;a href=&quot;http://www.engineyard.com/company/press/2010-09-21-engine-yard-congratulates-jruby-team-on-winning-idg%E2%80%99s-infoworld-bossie-award&quot;&gt;InfoWorld誌による（Best Open Source Application Development Software）部門Bossie賞の受賞&lt;/a&gt;です。&lt;br /&gt;これで「InfoWorld誌が認めたRuby言語実装」と書いても差し支えありませんね。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;次はあなたの番です&lt;/h2&gt;&lt;br /&gt;さあ、あなたもJRubyコミュニティに参加してみませんか。&lt;br /&gt;あなたの地域のJava、Ruby、OO、その他テクノロジー関係のグループで発表したり、コーディングイベントを主催してみませんか。&lt;br /&gt;近くのカンファレンスでの発表はどうですか。&lt;br /&gt;自分のプロジェクトにJRubyを使ってみて、JRubyが改良すべき点などを教えて下さい。&lt;br /&gt;ブログ記事を書いたり、スクリーンキャストを収録されてはどうですか。&lt;br /&gt;JRubyがどんなに素晴らしいか、友人に伝えて下さい。&lt;br /&gt;&lt;a href=&quot;http://jira.codehaus.org/secure/IssueNavigator.jspa?reset=true&amp;amp;jqlQuery=project+%3D+JRUBY+AND+created+%3E%3D+-30d+ORDER+BY+created+DESC&quot;&gt;JRubyのトラッカー&lt;/a&gt;を眺めたり、&lt;a href=&quot;https://github.com/jruby/jruby/tree/master/spec/tags&quot;&gt;今動かないRubySpecs&lt;/a&gt;を見たり&lt;br /&gt;&lt;a href=&quot;http://groups.google.com/group/jruby-users&quot;&gt;メーリングリスト&lt;/a&gt;で話題になっている問題などを読んで、貢献出来るかどうか見てみて下さい。&lt;br /&gt;&lt;a href=&quot;http://wiki.jruby.org&quot;&gt;JRuby wiki&lt;/a&gt;を読んでみて、改善すべき所を見つけたり、新しい記事を書いたり、或いは他の言語への翻訳などの手伝いをしてみませんか。&lt;br /&gt;Rubyを広める手伝いをお願いします。&lt;br /&gt;私達はJRubyをより良い物にする努力を続けて行きます。&lt;br /&gt;&lt;br /&gt;最後に…。あなたにとって印象深いJRubyの出来事は何でしたか。コメント欄でもいいですし、ブログ記事などでも構いません。お待ちしています。</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/6595633956095503556/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/12/jruby.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/6595633956095503556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/6595633956095503556'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/12/jruby.html' title='JRubyの一年を振り返って'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-3766986499539830551</id><published>2010-07-25T02:54:00.001-05:00</published><updated>2010-07-25T02:54:08.853-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="memory"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>Eclipse Memory AnalyzerでRubyアプリケーションのメモリリークを検知する</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://blog.headius.com/2010/07/finding-leaks-in-ruby-apps-with-eclipse.html&quot;&gt;原文&lt;/a&gt;: チャールズ＝オリバー＝ナター&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;前回の記事「&lt;a href=&quot;&quot;&gt;JRubyでメモリを観察するには&lt;/a&gt;」の後、何人かの人からEclipse MATのJRubyでの使い方について書いてみたらどうかとの意見を貰いました。これを早速取り上げる事にします。&lt;br /&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;&lt;a href=&quot;http://www.eclipse.org/mat/&quot;&gt;Eclipse Memory Analyzer&lt;/a&gt;は他のEclipseを基盤にしたアプリケーションの例に外れる事なく、起動すると基本ページから個々の作業向けのページへと移動します。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioLjkArn6CgMaZ268kxXnr3DMZE_2ifj8oFeFPHKWzvJqbzOvOjM-SL_rsL-cdmVmlFTv4eM6JsOlMWcRwrtwn1uf1-1pvObm85cA5AeyK1kMDxo0cC_v0UdgBW4joh86rHhc14hE9Nhj1/s1600/Screen+shot+2010-07-12+at+11.34.47+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 301px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioLjkArn6CgMaZ268kxXnr3DMZE_2ifj8oFeFPHKWzvJqbzOvOjM-SL_rsL-cdmVmlFTv4eM6JsOlMWcRwrtwn1uf1-1pvObm85cA5AeyK1kMDxo0cC_v0UdgBW4joh86rHhc14hE9Nhj1/s400/Screen+shot+2010-07-12+at+11.34.47+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493060081552421474&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;MATは、jhatに較べてもっとインタラクティブにヒープダンプを解析する事が出来ます。MATはjmapのダンプファイルを解析出来ますので、メモリリークを起こしているRailsのアプリケーションからダンプを取ってくる事にしましょう。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;このコントローラをアプリケーションに加えました。&lt;br /&gt;&lt;pre&gt;class LeakyController &amp;lt; ApplicationController&lt;br /&gt;  class MyData&lt;br /&gt;    def initialize(params)&lt;br /&gt;      @params = params&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  LEAKING_ARRAY = {}&lt;br /&gt;  def index&lt;br /&gt;    LEAKING_ARRAY[Time.now] = MyData.new(params)&lt;br /&gt;    render :text =&amp;gt; &quot;There are #{LEAKING_ARRAY.size} elements now!&quot;&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;どこかの秀才君が最近使われたリクエストへのパラメータを、時間をキーにカスタムタイプで包んで、定数としてLeakyControllerに後片づけする事なく保存する事にしたようですね。これは一時凌ぎなのかも知れませんし、もしかしたら開発スタッフの中にはオバカサンが紛れ込んでいるのかも知れません。いずれにしてもこれは検知して直す必要があります。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;このアプリケーションを動かして/leaky/indexを10000回ほど呼びます。There are 10000 elements now!と出力される筈です。&lt;br /&gt;&lt;pre&gt;~ &amp;#10132; ab -n 10000 http://localhost:3000/leaky&lt;br /&gt;This is ApacheBench, Version 2.3 &amp;lt;$Revision: 655654 $&amp;gt;&lt;br /&gt;Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/&lt;br /&gt;Licensed to The Apache Software Foundation, http://www.apache.org/&lt;br /&gt;&lt;br /&gt;Benchmarking localhost (be patient)&lt;br /&gt;Completed 1000 requests&lt;br /&gt;Completed 2000 requests&lt;br /&gt;...&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;10000のリクエストを処理してしまった後も、アプリケーションのメモリ消費量は、ヒープが一杯になるまで増加の一途を辿ることが解ると思います。（JRubyはJVMで走りますから最大ヒープ量を自動的に設定します。）jmapを使って調査を始めましょう。&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;~ &amp;#10132; jps -l&lt;br /&gt;61976 org/jruby/Main&lt;br /&gt;61999 sun.tools.jps.Jps&lt;br /&gt;61837&lt;br /&gt;&lt;br /&gt;~ &amp;#10132; jmap -histo 61976 | grep &quot; ruby\.&quot; | head -5&lt;br /&gt; 37:         11685         280440  ruby.TZInfo.TimezoneTransitionInfo&lt;br /&gt; 40:         10000         240000  ruby.LeakyController.MyData&lt;br /&gt;133:           970          23280  ruby.Gem.Version&lt;br /&gt;137:           914          21936  ruby.Gem.Requirement&lt;br /&gt;170:           592          14208  ruby.TZInfo.TimezoneOffsetInfo&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;私達の旧友TimezonTransitionInfoがまた顔を覗かせていますが、これはもうお約束なので気にしない事にします。この、一見して10000個もあるLeakyController::MyDataってなんでしょうか。これはどこから来たのでしょう。これを参照しているオブジェクトなんでしょうか。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;ここから、メモリをダンプして、MATを使って解析したり、或いは、VisualVMでやるようにMATでダンプをとって一気に解析に移ったりする事が出来ます。ここではMATに全部やらせることにします。&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;MATにヒープを読ませる&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;（注記：ここまで記事を書いてきて、最新のOS X版のJava 6のjmapにはちょっとした欠陥がある事が判明しました。どうやらダンプされないオブジェクトが有るようなのです。結果的にダンプを解析しても表示されないフィールドやオブジェクトがあります。幸いにもSoylatteやOpenJDKのビルドにはこのような問題は存在しないようです。ここでは私がビルドしたOpenJDK 7を使います。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;ファイルメニューからAcquire Heap Dumpを選びます。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8aGJ0Ntr9CbzsMlS8RDSGI5xBIb5qy4TU17Cj0mkkyc3-QWVftke6tAZApLUWsZRODwH4J6Rdcfudm9oOOIgfSx5e_QM7ydBUlLdB62VfQnYCS5ii6TxcBc7-sUDtNgOkIz_BigtxQ_wy/s1600/Screen+shot+2010-07-12+at+12.03.03+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 214px; height: 108px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8aGJ0Ntr9CbzsMlS8RDSGI5xBIb5qy4TU17Cj0mkkyc3-QWVftke6tAZApLUWsZRODwH4J6Rdcfudm9oOOIgfSx5e_QM7ydBUlLdB62VfQnYCS5ii6TxcBc7-sUDtNgOkIz_BigtxQ_wy/s400/Screen+shot+2010-07-12+at+12.03.03+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493066581649909650&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;このダイアログは、前述のjpsコマンドが挙げるのと同じプロセスを表示しますから、解り易いと思います。（JDKのインストールディレクトリを指定しなければならない時は、Configureボタンを押して、jdkhomeフラグをHPROF jmap dump providerに指定して下さい。）&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBiX8EYi7sRfU73F9cySa4YngCX6YGNmQh5Bi352UWAddNL1FEVgCKptlE_tYiPiByODXSFOuoqVafsy8AXdM4wkFXSOJctvV4J67Udbs_OCBPPHCOg-xAkQYr7OeudwsgWbyq4RwPSlHy/s1600/Screen+shot+2010-07-12+at+12.04.08+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 305px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBiX8EYi7sRfU73F9cySa4YngCX6YGNmQh5Bi352UWAddNL1FEVgCKptlE_tYiPiByODXSFOuoqVafsy8AXdM4wkFXSOJctvV4J67Udbs_OCBPPHCOg-xAkQYr7OeudwsgWbyq4RwPSlHy/s400/Screen+shot+2010-07-12+at+12.04.08+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493066869060079170&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Railsアプリケーション（プロセスIDは61976）を選んで続行です。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;MATはプロセスに接続し、ヒープをディスクにダンプして、直ぐにこれを読み込みます。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDoJYDtkK9_9nwuw9bBt3Ui52Y9LwmI2aYA1AXHnSsrWyYzEKbA3OZfBuYimH1BmED6DqNqW9r4czAMQkVafv_Iqxbniy6FmpvdBHxMS75hjLFha9a6NAPvSsDbhJFbdwq3csvS072Ucau/s1600/Screen+shot+2010-07-12+at+12.05.49+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 162px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDoJYDtkK9_9nwuw9bBt3Ui52Y9LwmI2aYA1AXHnSsrWyYzEKbA3OZfBuYimH1BmED6DqNqW9r4czAMQkVafv_Iqxbniy6FmpvdBHxMS75hjLFha9a6NAPvSsDbhJFbdwq3csvS072Ucau/s400/Screen+shot+2010-07-12+at+12.05.49+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493067302661281122&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;ダンプの読み込みが終わると、次の選択肢は幾つか有ります。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWQ5Gitcsn-0KPTwCJ-bOaEyc05slmkneLfCHRTqELH1eKcfGG96bwF4fCXkJd2kmIXrP3EJeUTAzr4pZAzCGqdm2gswvYllEmKBySgwPIPvLIAm0MJ8z5mEtD6FP3FhkfLdwyLi6uz8Mr/s1600/Screen+shot+2010-07-12+at+12.07.12+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 321px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWQ5Gitcsn-0KPTwCJ-bOaEyc05slmkneLfCHRTqELH1eKcfGG96bwF4fCXkJd2kmIXrP3EJeUTAzr4pZAzCGqdm2gswvYllEmKBySgwPIPvLIAm0MJ8z5mEtD6FP3FhkfLdwyLi6uz8Mr/s400/Screen+shot+2010-07-12+at+12.07.12+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493067540433476098&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;日が違えば、コンポーネント毎にメモリ消費の多いオブジェクトを探して回ったり、或いは過去の解析結果を見直したりする事にもなるでしょうが、今回はMyDataのリークの解決が最優先なのでLeak Suspects Reportを走らせます。&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;リーク容疑者ですって?&lt;/h2&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjhu_-3XW4yvfvm3vanECR_AhBAdz5h2RYwt5x2unTOijiFO4RRn9PMSq7OUYImXLHLXPg_3mU0G7ETg1I_Xon0cgvnEbSya25RdYHQ8qN8QZjVqJm1Mr9G9Wb2KJsBJCHj05jR4_JqwQU/s1600/Screen+shot+2010-07-12+at+12.09.31+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 162px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjhu_-3XW4yvfvm3vanECR_AhBAdz5h2RYwt5x2unTOijiFO4RRn9PMSq7OUYImXLHLXPg_3mU0G7ETg1I_Xon0cgvnEbSya25RdYHQ8qN8QZjVqJm1Mr9G9Wb2KJsBJCHj05jR4_JqwQU/s400/Screen+shot+2010-07-12+at+12.09.31+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493068140135381202&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;メモリリークを起こしているかも知れないオブジェクトを探して回る事が出来るなんて便利なツールがあるなんて、冗談ではないんでしょうか。それが本当にあるんですのよ、奥様！&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;これは、ツールが星の数ほどあるJVMならではの長所だと思います。基本的なツールの数が多すぎて（メモリを調査するものだけで最低1ダースはあるでしょうから）デベロッパはメモリ解析等、特定の目的の為のツールへと移行して行ったのです。私がリーク追跡する時にはMATをよく使います。（jhatに較べてメモリ消費が少ないのでヒープをざっと読むにはとても都合がいいのです。）&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;さて、MATがヒープを読み込んだところで、メモリリークを起こしていそうなオブジェクトのチャートが表示されます。理論的には、オブジェクトが消費するメモリの量が、ヒープに存在する他のオブジェクトに較べて特別に多いものを探しているのです。今回の場合、MATは、合わせてヒープの半分以上を占めている容疑者を三つ挙げました。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVIrwqtG44sxMeTcoqdm22_lloCj-e8k4ycTFvuT0FY4PPGHSUnDky6NlSX2UugbhlwqeXI45WfpJnUayBav0dBrP3-_bzNTy7w4hr2ixfzwUSIrfnufLsHHCjf5pgs6UEWrJCJ2de1H1Q/s1600/Screen+shot+2010-07-12+at+12.15.12+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 275px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVIrwqtG44sxMeTcoqdm22_lloCj-e8k4ycTFvuT0FY4PPGHSUnDky6NlSX2UugbhlwqeXI45WfpJnUayBav0dBrP3-_bzNTy7w4hr2ixfzwUSIrfnufLsHHCjf5pgs6UEWrJCJ2de1H1Q/s400/Screen+shot+2010-07-12+at+12.15.12+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493070093160401490&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;下へスクロールしてこれらを見てみましょう。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNZH2Xd3Ic7u4VdjZaakMQ9ZI8F4YBl1UKhpjot8KNVwE9bBh11uNsXDTzFbvtoGFSBkF2AfHv5_7BLZELoDibcHdXRkPPjnTY2jrjlXDIighJt2zMBhoh44j9Z6D3XL2_RoVQcY8_i_xq/s1600/Screen+shot+2010-07-12+at+12.18.37+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 352px; height: 400px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNZH2Xd3Ic7u4VdjZaakMQ9ZI8F4YBl1UKhpjot8KNVwE9bBh11uNsXDTzFbvtoGFSBkF2AfHv5_7BLZELoDibcHdXRkPPjnTY2jrjlXDIighJt2zMBhoh44j9Z6D3XL2_RoVQcY8_i_xq/s400/Screen+shot+2010-07-12+at+12.18.37+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493070607597452626&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;容疑者のリストには、Hashが一つ、Moduleが一つ、そして711個のClassオブジェクトが含まれているようですね。JRubyが使う、コアクラスとRailsとそしてRailsが依存するライブラリに含まれるクラスの数は容易に数百に上りますから、Classオブジェクトはここでは無視します。4MBも消費している巨大なModuleがありますが、これについては後述します。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Hashが第一容疑者ですね。これを拡大してみましょう。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;新しく表示された情報の一番上のものは「accumulation point」への「最短パス」のリストです。「accumulation point」というのは、リークを起こしていそうなデータが集まっている場所の事です。ただ集まっているだけではないのですが、ここでは一部だけを見ています。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ0Ee-86WvZzOSUOgasR-EgMwL_d0fQ0AC_IZMunl33N_N4Wb8t__bOSu4-xopuwZv38r5pm6g5BAPVDDEzJrw4orDiyh7K5xQDv0mNP52GaLpGg_RJGfzM3di1Ihu1kP-wioTECWU-1RJ/s1600/Screen+shot+2010-07-12+at+12.22.36+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 314px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ0Ee-86WvZzOSUOgasR-EgMwL_d0fQ0AC_IZMunl33N_N4Wb8t__bOSu4-xopuwZv38r5pm6g5BAPVDDEzJrw4orDiyh7K5xQDv0mNP52GaLpGg_RJGfzM3di1Ihu1kP-wioTECWU-1RJ/s400/Screen+shot+2010-07-12+at+12.22.36+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493071970837876418&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;このリストの一番上には、始めに容疑者として挙げられたRubyHashオブジェクトと、それへと連なるオブジェクトの列が表示されています。この場合、Hash自体からConcurrentHashMap、そしてClassオブジェクトのconstantsフィールドへと参照の連鎖を辿って行けます。（ここでは何も隠された要素がないと言う事に注意して下さい。）たったこれだけで何かしらのClassがこのHashオブジェクトを定数として保有している事が解りました。凄いでしょう。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;念の為、本当にこのオブジェクトに問題がある事を確認します。もう少し下へとスクロールするとこのHashが集めたオブジェクトのリストが有りますので、これを見てみましょう。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9F3w2ug_j2JfpOLv__mXfHTKuPIemNLU-yr_dv6XwmpN19__MJ2E6bXm3zVsakJ2qsVKmPE-MrDl6CfW5DaShDYrRSJhgKS_j1sLMn39HYCsGTexh3MXxl7e4VlFjhPx2o3q1V8FdnCF8/s1600/Screen+shot+2010-07-12+at+12.27.55+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 150px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9F3w2ug_j2JfpOLv__mXfHTKuPIemNLU-yr_dv6XwmpN19__MJ2E6bXm3zVsakJ2qsVKmPE-MrDl6CfW5DaShDYrRSJhgKS_j1sLMn39HYCsGTexh3MXxl7e4VlFjhPx2o3q1V8FdnCF8/s400/Screen+shot+2010-07-12+at+12.27.55+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493072990336500642&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;ハッシュテーブルの項目が並んでいますが、もっと詳しく見る事は出来ないものでしょうか。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;この項目もクリック出来ますから、どんどんクリックして中身を覗いて行きましょう。項目をクリックすると何が集まったのか解ります。List Objectsメニュー、そしてサブメニューからwith Outgoing Referencesを選びます。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUY0zX9Bz-8ym6SjFcn-wdenmgDkfDnuuBiO1zn23TY5tMH4QyAtWZ3WrXIgko8uYy2rO4FY4PXP7B97EKCRyMXMIzRDXhGmLpgULMuer_CaFpZhmKwgvvA94ZiltMN09a772oQzDt0tux/s1600/Screen+shot+2010-07-12+at+12.35.15+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 192px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUY0zX9Bz-8ym6SjFcn-wdenmgDkfDnuuBiO1zn23TY5tMH4QyAtWZ3WrXIgko8uYy2rO4FY4PXP7B97EKCRyMXMIzRDXhGmLpgULMuer_CaFpZhmKwgvvA94ZiltMN09a772oQzDt0tux/s400/Screen+shot+2010-07-12+at+12.35.15+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493074941782781698&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;このRubyHashEntryに隠されたMyDataオブジェクトが漸く見えてきました。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8dY2SiTHA-PwxXzbfuLy8KFQm0Pax1O80e_8SDn46XUCMijCqUPP1rvk69hDMklm1TjZg3ugyEcF0uVWYEtCWEHoBecOpEAYyPCfFvhvDwV1PJFtEP3lc-759js6ZE_SmLX0dEpAH7qKG/s1600/Screen+shot+2010-07-12+at+12.40.23+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 162px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8dY2SiTHA-PwxXzbfuLy8KFQm0Pax1O80e_8SDn46XUCMijCqUPP1rvk69hDMklm1TjZg3ugyEcF0uVWYEtCWEHoBecOpEAYyPCfFvhvDwV1PJFtEP3lc-759js6ZE_SmLX0dEpAH7qKG/s400/Screen+shot+2010-07-12+at+12.40.23+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493076096507480514&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;これでこのRubyHashが目的のデータである事が確認出来ました。更に、このオブジェクトのキーはTimeオブジェクト（org.jruby.RubyTime オブジェクト）である事も合わせて知ることが出来ました。「最短パス」画面に戻って、このオブジェクトを保有しているConcurrentHashMapについてもう少し詳しく調べてみましょう。このマップのエントリーは定数をキーにしていますから、どのキーがメモリリークを起こしているデータを参照しているかが解る筈です。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;（OpenJDK 7を使った事でメモリアドレスが変わっている事に注意して下さい。データの構造に変化は有りません。）&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4M1GudXQhLhyphenhyphenBYeM45BFSa6HmkslnSqGNK8NO01p1iryO3HXfxNFF_79NszZ7e_MWl566fUDXHUCDoO9upD33deUVE3hhgsTsMxGoaOoIMSftuwAjZ1oh24rGsL9EOUky9za5O0xG_0Hg/s1600/Screen+shot+2010-07-12+at+1.50.21+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 69px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4M1GudXQhLhyphenhyphenBYeM45BFSa6HmkslnSqGNK8NO01p1iryO3HXfxNFF_79NszZ7e_MWl566fUDXHUCDoO9upD33deUVE3hhgsTsMxGoaOoIMSftuwAjZ1oh24rGsL9EOUky9za5O0xG_0Hg/s400/Screen+shot+2010-07-12+at+1.50.21+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493094187536718210&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;注目のRubyHashを直に参照しているHashEntryオブジェクトから今一度「List Objects」「with Outgoing References」をやります。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis2p6GgAKRI7Vwwm_YxO95KFN5Vkx3dNk69cuaenXM3YXoDkzng6SG0rUlwlW-ftHq3arRVfz41sGyo-wpchN7UQOfMLmcrRTKYIcgT9bbyb0nNsFlUBRNgtue_4N5jAOQ9KMNQRJluKpQ/s1600/Screen+shot+2010-07-12+at+1.52.24+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 88px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis2p6GgAKRI7Vwwm_YxO95KFN5Vkx3dNk69cuaenXM3YXoDkzng6SG0rUlwlW-ftHq3arRVfz41sGyo-wpchN7UQOfMLmcrRTKYIcgT9bbyb0nNsFlUBRNgtue_4N5jAOQ9KMNQRJluKpQ/s400/Screen+shot+2010-07-12+at+1.52.24+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493094724104187682&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;ありました！HashEntryのkeyのところに定数「LEAKING_ARRAY」がありました。&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;例のModuleは？&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;メモリリークの容疑者に挙げられていたModuleはどうしたんでしょう。ヒープで4MBものスペースを占有していました。これも調べてみましょう。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDRHk8VtCqgfrSAShDq3USTFOJfqVEXzv9P1HrkJ6O2drHjdZb1U4rIjKTZlCHBN_oQHmJ-OLG5gQi1dJTEw6X_A0GWzfCtJsuQ5ZirpEj4VmDqVv5M8pfq16hbXU-GFZ0t-pc3yuklS_b/s1600/Screen+shot+2010-07-12+at+2.09.56+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 182px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDRHk8VtCqgfrSAShDq3USTFOJfqVEXzv9P1HrkJ6O2drHjdZb1U4rIjKTZlCHBN_oQHmJ-OLG5gQi1dJTEw6X_A0GWzfCtJsuQ5ZirpEj4VmDqVv5M8pfq16hbXU-GFZ0t-pc3yuklS_b/s400/Screen+shot+2010-07-12+at+2.09.56+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493099194527999122&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;ああ、どうやらEclipse MATはGemモジュールにメモリリークの容疑を掛けたようですね。何故でしょう。もう一度レポートに戻って、下の方にある「Accumulated Objects by Class table」を見てみましょう。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiwOkLsgZ4XkC-1j2wlQ5YAjKWvcU9aXNkeUa-HttZgsdbp8r44RnjvJ56zyCwGJlpAVXx_eA2i3tgcuUA0YeebzKqJiJlgHQjHuN-e2v7_WVSC3GHuCQIVbEyIEzCdefdZ0xRwSiYIY6I/s1600/Screen+shot+2010-07-12+at+2.21.12+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 110px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiwOkLsgZ4XkC-1j2wlQ5YAjKWvcU9aXNkeUa-HttZgsdbp8r44RnjvJ56zyCwGJlpAVXx_eA2i3tgcuUA0YeebzKqJiJlgHQjHuN-e2v7_WVSC3GHuCQIVbEyIEzCdefdZ0xRwSiYIY6I/s400/Screen+shot+2010-07-12+at+2.21.12+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493102103334413218&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Gemモジュールが最終的には&lt;strike&gt;6000&lt;/strike&gt;ものGem::Specificationオブジェクト（3.8MBを占有しています）を参照する事が見て取れます。（&lt;strike&gt;ところで手元には6000ものgemは決してインストールされてはいません。&lt;/strike&gt;これはRubyGemsのバグなのかも知れません。もしかしたらJRubyとEclispe MATを使う事でRubyGemsのメモリリーク、又はメモリの浪費を発見したのかも知れませんね。）&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Evan Phoenix氏によると私は結果を読み間違っていたようです。Specificationオブジェクトの数は249で、「self」のサイズがおよそ6000バイト、そしてその占めるメモリの量が3.8MBということです。では、MATのもう一つのフィーチャであるCustomized Retained Set計算を使って説明します。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;今、保有されているメモリの量がちょっと怪しいですよね。本当に3.8MBものメモリがGem::Specificationsオブジェクトによって保有されているのでしょうか。多すぎると思いますよね。でもGemモジュールの参照を順々に追って行くのは大変面倒です。無駄なデータを省くのに何か良い手段はないものでしょうか。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;まず最初にGemモジュール画面に注目します。メモリリークの第二容疑者として挙げられているところの、「Shortest Paths」を拡大します。一番上のRubyModuleがGemモジュールで、ここからCustomized Retained Setを計算します。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7h0W_KkNA3jvzCyaBi46Sgdbp4xZD-AVH8-AKa_AWG1BXHuqObnRS3X-dc8V3rnR7EcOzCWyj9U-YfHxlodf1Mzlllr6uVMZfddpIr8Ka_0uiaqWYjNvivEngABZiTLbPJlAlx_5PSXpI/s1600/Screen+shot+2010-07-12+at+7.21.11+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 147px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7h0W_KkNA3jvzCyaBi46Sgdbp4xZD-AVH8-AKa_AWG1BXHuqObnRS3X-dc8V3rnR7EcOzCWyj9U-YfHxlodf1Mzlllr6uVMZfddpIr8Ka_0uiaqWYjNvivEngABZiTLbPJlAlx_5PSXpI/s400/Screen+shot+2010-07-12+at+7.21.11+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493179467687902450&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;出て来るダイアログでは計算の為のオプションを指定する事が出来ます。ここでは、Gem::SpecificationがRubyのクラスとモジュールを参照している部分を除くのが目的ですので、単純にorg.jruby.RubyClassとorg.jruby.RubyModuleを無視することします。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6MybYlA25UHBPh8Szu3H2HDO3bC5NAQ84E5HLyjNp7NfjY77EfLrhRmRtMnlaCCBXUMyufJ2rtw1dwkOjUJajVI5D4XLmcHeOVP6PS9XAWLrNOaqZMq7RnCsKOgSWtg97NkE7Pj5yteag/s1600/Screen+shot+2010-07-12+at+7.24.50+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 315px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6MybYlA25UHBPh8Szu3H2HDO3bC5NAQ84E5HLyjNp7NfjY77EfLrhRmRtMnlaCCBXUMyufJ2rtw1dwkOjUJajVI5D4XLmcHeOVP6PS9XAWLrNOaqZMq7RnCsKOgSWtg97NkE7Pj5yteag/s400/Screen+shot+2010-07-12+at+7.24.50+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493180393104038482&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;結果は前に見たものと似ていますが、保有されているヒープの量で並べられています。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWpIT4dW_noVtKfFj1XG5hswxLFwI5Jd2R2CxxPsTJnG6hdmrti67Uvt3CJp9gDrkZ7xhroKix4nGoBeXAVbjzqqGeQl5JaxFt6Gjw4EdFyZYWY-8sCOmUVtTlOFl2J4Ugzc1DEyGJ3MFB/s1600/Screen+shot+2010-07-12+at+7.27.48+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 171px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWpIT4dW_noVtKfFj1XG5hswxLFwI5Jd2R2CxxPsTJnG6hdmrti67Uvt3CJp9gDrkZ7xhroKix4nGoBeXAVbjzqqGeQl5JaxFt6Gjw4EdFyZYWY-8sCOmUVtTlOFl2J4Ugzc1DEyGJ3MFB/s400/Screen+shot+2010-07-12+at+7.27.48+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493183846946721154&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;どういう事でしょうか。全てStringデータのようですね。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;JRubyのStringクラスの実装はorg.jruby.RubyStringオブジェクトで行っていますが、それにはorg.jruby.util.ByteListオブジェクトを集め、更にorg.jruby.util.ByteListオブジェクトはJavaのbyte配列を集めたものを用いています。ですから、このリストの上位三つは実質的にはStringと同等であると言えます。これがどこから来ているのかを捜査する最善の方法は、RubyStringについて「List Object」「with Incoming References」をする事でしょう。&lt;br /&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqK1mSNjNCA9xOHRKkcItb6hEKcu9nfj_pk3vqxFf4YIeXZS2KRmgX1K_8du3ogWe2BnLT66Z5Hj6kezd8ULf_0dcK-odTSVkwZ4YNfQLRMB84u2CT2R8x0Aq5ptFveG9tIfSvWGbqRm-R/s1600/Screen+shot+2010-07-12+at+7.44.44+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 321px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqK1mSNjNCA9xOHRKkcItb6hEKcu9nfj_pk3vqxFf4YIeXZS2KRmgX1K_8du3ogWe2BnLT66Z5Hj6kezd8ULf_0dcK-odTSVkwZ4YNfQLRMB84u2CT2R8x0Aq5ptFveG9tIfSvWGbqRm-R/s400/Screen+shot+2010-07-12+at+7.44.44+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493185642045248162&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;やっと、どこからStringがやって来るのかを一望出来る画面が出ました。始めの方にあるものを幾つか調べてみると、それがGemモジュールにある定数のテーブルに有るものだと解ります。これは大した問題ではなさそうですが、RubyStringオブジェクトを保有しているメモリの量の順に並べ替えると、システムの様子が少し違って見えます。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTO4vfI_6ZG4VHGRMD5mWVPBT3KdRCBuXkzkZBtcTgj3XkTtCf1ffRvwlsVs2GMD7eURij5Ub038Yp0PM9yZi3HCQibULIuCA7w83nXd82l4hPiltFsiFRPHR9hGgMJuvcOFf7Zxs-rduV/s1600/Screen+shot+2010-07-12+at+8.07.09+PM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 272px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTO4vfI_6ZG4VHGRMD5mWVPBT3KdRCBuXkzkZBtcTgj3XkTtCf1ffRvwlsVs2GMD7eURij5Ub038Yp0PM9yZi3HCQibULIuCA7w83nXd82l4hPiltFsiFRPHR9hGgMJuvcOFf7Zxs-rduV/s400/Screen+shot+2010-07-12+at+8.07.09+PM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5493191433094785250&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;最大のStringオブジェクトを掘り下げてみると、これはGem::Specificationのインスタンス変数に保有されているように見えますね。これはもう少し調べてみる価値がありそうです。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Rubyアプリケーションには押し並べて沢山のStringがあるものです。これだけでは特に変わった事では有りませんが、（バイトそのものに至る迄の）非効率を調査出来るようなツールが有り、またGemモジュールで保有されているデータの一部はクラス序列への参照ではない、「本物」であると知るのは気持ちのいいものです。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;（でもこのようなStringの全てがヒープに残っているのがよいかどうかはまだ納得していません。でもこれから先の調査は読者への宿題にします。）&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;あなたの番です&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;Eclipse MATは無料で手に入るツールのうち、恐らく最善の物の一つです。オブジェクトの閲覧、メモリリークの検知、GCのルート解析、オブジェクトのクエリ言語の他にも、数多くのフィーチャが本体と第三者からのプラグインには有ります。メモリリークを追いかけていたり、或いは手元の(J)Rubyアプリケーションのメモリ消費を調べてみたいという場合、MATは試してみる価値のあるツールです。（そして、その結果を是非知らせて下さい。）&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/3766986499539830551/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/07/eclipse-memory-analyzerruby.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/3766986499539830551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/3766986499539830551'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/07/eclipse-memory-analyzerruby.html' title='Eclipse Memory AnalyzerでRubyアプリケーションのメモリリークを検知する'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioLjkArn6CgMaZ268kxXnr3DMZE_2ifj8oFeFPHKWzvJqbzOvOjM-SL_rsL-cdmVmlFTv4eM6JsOlMWcRwrtwn1uf1-1pvObm85cA5AeyK1kMDxo0cC_v0UdgBW4joh86rHhc14hE9Nhj1/s72-c/Screen+shot+2010-07-12+at+11.34.47+AM.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-4926022619220969698</id><published>2010-07-24T09:53:00.001-05:00</published><updated>2010-07-24T09:53:51.361-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="1.5.0"/><category scheme="http://www.blogger.com/atom/ns#" term="1.6.0"/><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="JVM"/><category scheme="http://www.blogger.com/atom/ns#" term="tips"/><category scheme="http://www.blogger.com/atom/ns#" term="tools"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRubyのメモリを観察するには</title><content type='html'>&lt;a href=&quot;http://blog.headius.com/2010/07/browsing-memory-jruby-way.html&quot;&gt;原文&lt;/a&gt;: チャールズ＝オリバー＝ナター &lt;br /&gt;&lt;p&gt;&lt;br /&gt;Ruby言語の各実装において、どんなメモリ消費を解析するツールがあるのかが近頃ちょっとした話題になっています。 それもその筈、Rubyで書かれたアプリケーションの（不具合の調査は言うに及ばず）メモリ消費の具合を詳しく調べるのは容易い事ではありません。 JRubyを使わないのなら、そうです。 &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;JRubyはJVM上で走るので、JVM向けに作られた何十ものツールの恩恵に授かる事が出来ます。 中にはJDKに同梱されているものを含め、メモリの調査、解析、レポートをするものもあります。 ヒープダンプが欲しければ、Hotspot系のJVM（SunまたはOpenJDK）に含まれるjmapやjhatが使えます。 もっと高度なツールが欲しければ、Eclipseを基にしたMemory Analysis Tool、 メモリ及びCPU性能解析ツールであるYourKit、 今ではHotspotに含まれているJavaVMを始め、 数多くの選択肢があります。 こうした数多くのツールのお陰でメモリの調査には事欠きません。 &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;本稿では実際にこのうちの二つのツールをどの様に使いこなすか見ていく事にします。 取り上げたツールは起動中のJVMを観察するグラフィカルなツールであるVisualVMと、 ヒープをダンプして事後解析を可能にするjmapとjhatのタッグチームです。 &lt;br /&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;h2&gt;&lt;br /&gt;準備 &lt;br /&gt;&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;ここで紹介するツールはJRubyのどのバージョンでも使う事が出来ますが、JRuby 1.6の開発に当たり、 様々な改良を施してあります。 特記すべきは、RubyでのオブジェクトとJavaに於けるオブジェクトが並んで表示されるようにしてある点です。 ここでもう少し解説しましょう。 &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;JRubyではRubyでのコアクラスは全てJavaネーティブのクラスで表されています。RubyのObjectクラスはorg.jruby.RubyObjectで、Stringクラスはorg.jruby.RubyStringで、と言った具合です。通常、コアクラスを拡張する場合、Javaネーティブのクラスをわざわざ書き出したりはしません。替わりに、ユーザによって作り出されるObjectを拡張するRubyObjectがメモリに出現するのです。このやり方には実によい用途があります。即ち、RubyObjectの中を覗いてmetaClassがどのRubyクラスを指しているかを調べるという用途が。 &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;出発点が解るよう、これがどんな風になっているのかを見てみましょう。独自のクラスを生成し、一万個のオブジェクトを生成し、保存して、その後スリープするスクリプトを動かします。 &lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ cat foo_heap_example.rb &lt;br /&gt;class Foo&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;ary = []&lt;br /&gt;10000.times { ary &amp;lt;&amp;lt; Foo.new }&lt;br /&gt;&lt;br /&gt;puts &quot;ready for analysis!&quot;&lt;br /&gt;sleep&lt;br /&gt;&lt;br /&gt;~/projects/jruby ➔ jruby foo_heap_example.rb &lt;br /&gt;ready for analysis!&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;これで実験の準備は出来ました。jmapを使用するに当たってこのスクリプトのプロセスIDが必要です。使い慣れたシェルコマンドを使う事も勿論出来ますが、JDKにはJVMのプロセスIDを集める為のツールが同梱されていますのでこれを使います。jpsというツールです。 &lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ jps -l&lt;br /&gt;52862 sun.tools.jps.Jps&lt;br /&gt;52857 org/jruby/Main&lt;br /&gt;48716 com.sun.enterprise.glassfish.bootstrap.ASMain&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;これから、私は三つのJVMプロセスを走らせている事が判ります。一つはjpsそのもの、もう一つは先程実験の為に走らせたJRuby、そしてもう一つは、ついさっきテスト用にスタートさせたGlassfishサーバです。興味があるのはJRubyですから、プロセスIDは52857です。jmapでこれをどのように扱うか見てみましょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ jmap&lt;br /&gt;Usage:&lt;br /&gt;    jmap [option] &amp;lt;pid&amp;gt;&lt;br /&gt;        (to connect to running process)&lt;br /&gt;    jmap [option] &amp;lt;executable &amp;lt;core&amp;gt;&lt;br /&gt;        (to connect to a core file)&lt;br /&gt;    jmap [option] [server_id@]&amp;lt;remote server IP or hostname&amp;gt;&lt;br /&gt;        (to connect to remote debug server)&lt;br /&gt;&lt;br /&gt;where &amp;lt;option&amp;gt; is one of:&lt;br /&gt;    &amp;lt;none&amp;gt;               to print same info as Solaris pmap&lt;br /&gt;    -heap                to print java heap summary&lt;br /&gt;    -histo[:live]        to print histogram of java object heap; if the &quot;live&quot;&lt;br /&gt;                         suboption is specified, only count live objects&lt;br /&gt;    -permstat            to print permanent generation statistics&lt;br /&gt;    -finalizerinfo       to print information on objects awaiting finalization&lt;br /&gt;    -dump:&amp;lt;dump-options&amp;gt; to dump java heap in hprof binary format&lt;br /&gt;                         dump-options:&lt;br /&gt;                           live         dump only live objects; if not specified,&lt;br /&gt;                                        all objects in the heap are dumped.&lt;br /&gt;                           format=b     binary format&lt;br /&gt;                           file=&amp;lt;file&amp;gt;  dump heap to &amp;lt;file&amp;gt;&lt;br /&gt;                         Example: jmap -dump:live,format=b,file=heap.bin &amp;lt;pid&amp;gt;&lt;br /&gt;    -F                   force. Use with -dump:&amp;lt;dump-options&amp;gt; &amp;lt;pid&amp;gt; or -histo&lt;br /&gt;                         to force a heap dump or histogram when &amp;lt;pid&amp;gt; does not&lt;br /&gt;                         respond. The &quot;live&quot; suboption is not supported&lt;br /&gt;                         in this mode.&lt;br /&gt;    -h | -help           to print this help message&lt;br /&gt;    -J&amp;lt;flag&amp;gt;             to pass &amp;lt;flag&amp;gt; directly to the runtime system&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;出てきたオプションのうち、一番簡潔なものは-histoです。これでヒープに格納されているオブジェクトをヒストグラムで出力します。これをJRubyのプロセスに使ってみます。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ jmap -histo:live 52857&lt;br /&gt;&lt;br /&gt; num     #instances         #bytes  class name&lt;br /&gt;----------------------------------------------&lt;br /&gt;   1:         22677        3192816  &amp;lt;constMethodKlass&amp;gt;&lt;br /&gt;   2:         22677        1816952  &amp;lt;methodKlass&amp;gt;&lt;br /&gt;   3:         35089        1492992  &amp;lt;symbolKlass&amp;gt;&lt;br /&gt;   4:          2860        1389352  &amp;lt;instanceKlassKlass&amp;gt;&lt;br /&gt;   5:          2860        1193536  &amp;lt;constantPoolKlass&amp;gt;&lt;br /&gt;   6:          2798         739264  &amp;lt;constantPoolCacheKlass&amp;gt;&lt;br /&gt;   7:          5861         465408  [B&lt;br /&gt;   8:          5399         298120  [C&lt;br /&gt;   9:          3042         292032  java.lang.Class&lt;br /&gt;  10:          4037         261712  [S&lt;br /&gt;  11:         10002         240048  org.jruby.RubyObject&lt;br /&gt;  12:          3994         179928  [[I&lt;br /&gt;  13:          5474         131376  java.lang.String&lt;br /&gt;  14:          1661          95912  [I&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;出力結果はJVMのシステムに存在している文字通り全てのオブジェクト（JRubyに全く関係の無いものまで）を表示します。この結果の価値は明らかでしょう。自分で書いたコードのメモリ消費だけではなく、同じプロセス内に存在している全てのライブラリ、全てのコードを、バイト配列（上記の[B）やJavaのString（上記の&quot;java.lang.String&quot;）に至るまで全て調べる事が出来ます。特別JRubyに関わる事は何もやっていません。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;本題に戻りましょう。 僕らの書いたFooクラスは一体どこへ行ったのでしょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;答えは実は目の前にあります。10002個あるorg.jruby.RubyObjectのうち、10000個はFooオブジェクトに他なりません。残り二つはRubyランタイムが作った何かでしょうが、この出力結果からは残念ながら区別出来ません。JRuby1.6ではこれが改善されます。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;今開発中のブランチではユーザによって作り出されるRubyのクラスにJavaのクラスをあてがう為のオプションを使う事が出来ます。これを使うともっと使い勝手のよいプロファイル結果を得るなどの利点があります。このオプションを使ってみましょう。（1.6リリースまでには、これがデフォルトになるか、或いはこのように長いオプションを使わずに済むようになると思います。） &lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ jruby -J-Djruby.reify.classes=true foo_heap_example.rb &lt;br /&gt;ready for analysis!&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;このプロセスにjmapを使うと、さっきのよりも面白い結果が得られます。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt; num     #instances         #bytes  class name&lt;br /&gt;----------------------------------------------&lt;br /&gt;   1:         22677        3192816  &amp;lt;constMethodKlass&amp;gt;&lt;br /&gt;   2:         22677        1816952  &amp;lt;methodKlass&amp;gt;&lt;br /&gt;   3:         35089        1492992  &amp;lt;symbolKlass&amp;gt;&lt;br /&gt;   4:          2860        1389352  &amp;lt;instanceKlassKlass&amp;gt;&lt;br /&gt;   5:          2860        1193536  &amp;lt;constantPoolKlass&amp;gt;&lt;br /&gt;   6:          2798         739264  &amp;lt;constantPoolCacheKlass&amp;gt;&lt;br /&gt;   7:          5863         465456  [B&lt;br /&gt;   8:          5401         298208  [C&lt;br /&gt;   9:          3042         292032  java.lang.Class&lt;br /&gt;  10:          4037         261712  [S&lt;br /&gt;&lt;b&gt;  11:         10000         240000  ruby.Foo&lt;/b&gt;&lt;br /&gt;  12:          3994         179928  [[I&lt;br /&gt;  13:          5476         131424  java.lang.String&lt;br /&gt;  14:          1661          95912  [I&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;Fooクラスがあるのが一目瞭然ですね。&quot;reify classes&quot;オプションにより、Rubyクラスと同じ名前のJVMクラスが、ruby.という接頭辞付きで生成されました。まだまだ小手調べですが、JVMのツールの本当の力を垣間見る事が出来るようになります。簡素なRailsアプリケーションを走らせて、結果を見てみましょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ jmap -histo:live 52926 | grep &quot; ruby.&quot;&lt;br /&gt;  29:         11685         280440  ruby.TZInfo.TimezoneTransitionInfo&lt;br /&gt;  97:           970          23280  ruby.Gem.Version&lt;br /&gt;  98:           914          21936  ruby.Gem.Requirement&lt;br /&gt; 122:           592          14208  ruby.TZInfo.TimezoneOffsetInfo&lt;br /&gt; 138:           382           9168  ruby.Gem.Dependency&lt;br /&gt; 159:           265           6360  ruby.Gem.Specification&lt;br /&gt; 201:           142           3408  ruby.ActiveSupport.TimeZone&lt;br /&gt; 205:           118           2832  ruby.TZInfo.DataTimezoneInfo&lt;br /&gt; 206:           118           2832  ruby.TZInfo.DataTimezone&lt;br /&gt; 273:            41            984  ruby.Gem.Platform&lt;br /&gt; 383:            14            336  ruby.Mime.Type&lt;br /&gt; 403:            13            312  ruby.Set&lt;br /&gt; 467:             8            192  ruby.ActionController.MiddlewareStack.Middleware&lt;br /&gt; 476:             8            192  ruby.ActionView.Template&lt;br /&gt; 487:             7            168  ruby.ActionController.Routing.DividerSegment&lt;br /&gt; 508:             6            144  ruby.TZInfo.LinkedTimezoneInfo&lt;br /&gt; 523:             6            144  ruby.TZInfo.LinkedTimezone&lt;br /&gt; 810:             4             96  ruby.ActionController.Routing.DynamicSegment&lt;br /&gt;2291:             2             48  ruby.ActionController.Routing.Route&lt;br /&gt;2292:             2             48  ruby.I18n.Config&lt;br /&gt;2293:             2             48  ruby.ActiveSupport.Deprecation.DeprecatedConstantProxy&lt;br /&gt;2298:             2             48  ruby.ActionController.Routing.ControllerSegment&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;ruby.を含む結果だけに絞りました。実に素晴らしい結果です。不可思議な事に970個ものGem::Versionオブジェクトが少なくとも23280バイトを消費しているのが解ります。更に残念な事に11685個に及ぶTZInfo::TimezoneTransitionInfoのインスタンスが280440バイトを消費している事も解ります。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;さあ、使えるデータが出揃ってきたところでjmapとjhatについてもう少し詳しく見て行きましょう。 &lt;br /&gt;&lt;/p&gt;&lt;h2&gt;&lt;br /&gt;jmapとjhat&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;ご推察の通り、JRubyを開発するときに私はプロファイラーを多いに使います。かれこれ10個ほどのツールを使った事があると思いますが、最初に手が伸びるのは決まってjmapとjhatのコンビです。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;jmapの一番簡単な使い方は既に見ました。次はオフラインのヒープダンプを見てみます。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ jmap -dump:live,format=b,file=heap.bin 52926&lt;br /&gt;Dumping heap to /Users/headius/projects/jruby/heap.bin ...&lt;br /&gt;Heap dump file created&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;こんなに簡単に使えます。バイナリのダンプのファイル、heap.binは幾つかのツールで中身をみる事が出来ます。当然、jhatが使えますし、VisualVMやEclipse Memory Analysis Tool等も使えます。何かの標準に則ったフォーマットではありませんが、長い間そのフォーマットは変わっていません。jhatのオプションを見てみましょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ jhat&lt;br /&gt;ERROR: No arguments supplied&lt;br /&gt;Usage:  jhat [-stack &amp;lt;bool&amp;gt;] [-refs &amp;lt;bool&amp;gt;] [-port &amp;lt;port&amp;gt;] [-baseline &amp;lt;file&amp;gt;] [-debug &amp;lt;int&amp;gt;] [-version] [-h|-help] &amp;lt;file&amp;gt;&lt;br /&gt;&lt;br /&gt; -J&amp;lt;flag&amp;gt;          Pass &amp;lt;flag&amp;gt; directly to the runtime system. For&lt;br /&gt;     example, -J-mx512m to use a maximum heap size of 512MB&lt;br /&gt; -stack false:     Turn off tracking object allocation call stack.&lt;br /&gt; -refs false:      Turn off tracking of references to objects&lt;br /&gt; -port &amp;lt;port&amp;gt;:     Set the port for the HTTP server.  Defaults to 7000&lt;br /&gt; -exclude &amp;lt;file&amp;gt;:  Specify a file that lists data members that should&lt;br /&gt;     be excluded from the reachableFrom query.&lt;br /&gt; -baseline &amp;lt;file&amp;gt;: Specify a baseline object dump.  Objects in&lt;br /&gt;     both heap dumps with the same ID and same class will&lt;br /&gt;     be marked as not being &quot;new&quot;.&lt;br /&gt; -debug &amp;lt;int&amp;gt;:     Set debug level.&lt;br /&gt;       0:  No debug output&lt;br /&gt;       1:  Debug hprof file parsing&lt;br /&gt;       2:  Debug hprof file parsing, no server&lt;br /&gt; -version          Report version number&lt;br /&gt; -h|-help          Print this help and exit&lt;br /&gt; &amp;lt;file&amp;gt;            The file to read&lt;br /&gt;&lt;br /&gt;For a dump file that contains multiple heap dumps,&lt;br /&gt;you may specify which dump in the file&lt;br /&gt;by appending &quot;#&amp;lt;number&amp;gt;&quot; to the file name, i.e. &quot;foo.hprof#3&quot;.&lt;br /&gt;&lt;br /&gt;All boolean options default to &quot;true&quot;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;基本的にjhatにヒープダンプを投げてやれば、jhatは仕事を始めます。解析するヒープが大きいと-Jを使ってjhatを走らせるJVMにヒープ用のメモリを多くやらないといけない場合も稀にあります。Railsのアプリケーションを解析しますので、ちょっと多めにヒープメモリを与える事にします。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ jhat -J-Xmx200M heap.bin&lt;br /&gt;Reading from heap.bin...&lt;br /&gt;Dump file created Fri Jul 09 02:07:46 CDT 2010&lt;br /&gt;Snapshot read, resolving...&lt;br /&gt;Resolving 604115 objects...&lt;br /&gt;[much verbose logging elided for brevity]&lt;br /&gt;&lt;br /&gt;Chasing references, expect 120 dots........................................................................................................................&lt;br /&gt;Eliminating duplicate references........................................................................................................................&lt;br /&gt;Snapshot resolved.&lt;br /&gt;Started HTTP server on port 7000&lt;br /&gt;Server is ready.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;「サーバの準備完了」と出ました。何ですかそれは！Javaでは何でもかんでもサーバでやるんですか？ &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;まあ、ここでは実際使い勝手が良いので見逃す事にします。jhatはポート7000でウェブサーバを立ち上げました。これでバイナリの中身をマウスを使って調べる事が出来ます。どんなものでしょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-ArUhvLvbstNnje2F8Ui4fEZEqR_ydDC7Kaq947YzIHVfjQlADuhLpEb3lA-E2fGlVieLXju9uxH4URcKeXV2bkktzZlkI4_rYM9Fg6dG62tkpEqFL5Dx1qOt5yxUEOyJ64flDQQSYD0T/s1600/Screen+shot+2010-07-09+at+2.15.35+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 335px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-ArUhvLvbstNnje2F8Ui4fEZEqR_ydDC7Kaq947YzIHVfjQlADuhLpEb3lA-E2fGlVieLXju9uxH4URcKeXV2bkktzZlkI4_rYM9Fg6dG62tkpEqFL5Dx1qOt5yxUEOyJ64flDQQSYD0T/s400/Screen+shot+2010-07-09+at+2.15.35+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491802046240324178&quot; name=&quot;BLOGGER_PHOTO_ID_5491802046240324178&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;これが最初のページです。JVMクラスがリストされています。下へスクロールすると一般的な機能が幾つかあります。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjU6C9uGfgIfFHV2BDqGwKaddcBn4_qCZQHFhNeOaxSBfir4UKwb6WRqyjdU-628IPbuRr_Yp2SAAW8DUlj9tcqGUfIR7r5sOpkDRb4rWt0-i7nmSrgKkqhykt1cf_y5Su2yJiHNNmYGZb_/s1600/Screen+shot+2010-07-09+at+2.18.13+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 177px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjU6C9uGfgIfFHV2BDqGwKaddcBn4_qCZQHFhNeOaxSBfir4UKwb6WRqyjdU-628IPbuRr_Yp2SAAW8DUlj9tcqGUfIR7r5sOpkDRb4rWt0-i7nmSrgKkqhykt1cf_y5Su2yJiHNNmYGZb_/s400/Screen+shot+2010-07-09+at+2.18.13+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491802522423135538&quot; name=&quot;BLOGGER_PHOTO_ID_5491802522423135538&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ヒープのヒストグラムを選びます。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLRHokE0DfEytDlNiGC5QiSG9SUkabEIswzYPEHTwtj6tvr4pdtBoh4zIcWngWpDv2H3jdzSKahaTeQHThzla5ooU_bx5JK52vm-VnC6PPfv19jAZnceoz8Hr5RvCzSAYhVTqQxSPCHgo3/s1600/Screen+shot+2010-07-09+at+2.20.09+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 269px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLRHokE0DfEytDlNiGC5QiSG9SUkabEIswzYPEHTwtj6tvr4pdtBoh4zIcWngWpDv2H3jdzSKahaTeQHThzla5ooU_bx5JK52vm-VnC6PPfv19jAZnceoz8Hr5RvCzSAYhVTqQxSPCHgo3/s400/Screen+shot+2010-07-09+at+2.20.09+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491803088652218450&quot; name=&quot;BLOGGER_PHOTO_ID_5491803088652218450&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;沢山のオブジェクトがメモリを消費しているのが見て取れます。オブジェクトにはJVM固有のものもあれば、JRubyの実装の為の物も、Rubyのクラスからの物もあります。ここでもTZInfo::TimezonTransitionInfoがあるのが解りますね。クリックしてみましょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV_aJMIIuUCpXzAbiDDbU_apQGtRotpVMgJ7Td-KCXmOscw-SA-YdZ8U8PjJMRphRD_A_rTzuGcLH3E65cEGJrUhcOMxjGos9iGMVhvX9puRS8vZ5ExYU7uofwM4Dy4oQayNQNIU2Khm4g/s1600/Screen+shot+2010-07-09+at+2.23.16+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 328px; height: 400px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV_aJMIIuUCpXzAbiDDbU_apQGtRotpVMgJ7Td-KCXmOscw-SA-YdZ8U8PjJMRphRD_A_rTzuGcLH3E65cEGJrUhcOMxjGos9iGMVhvX9puRS8vZ5ExYU7uofwM4Dy4oQayNQNIU2Khm4g/s400/Screen+shot+2010-07-09+at+2.23.16+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491803858574960498&quot; name=&quot;BLOGGER_PHOTO_ID_5491803858574960498&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;クラスに関する情報だけで、これと言って余り面白いものはありませんね。しかし、この画面の一番下からTimezoneTransitionInfoのインスタンスを見る事が出来るようです。やってみましょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnvPcQ9SzAMmncqqgFbymXxmUv_ugbGUu7uqwU7wUTksU6KDjFxKP9njFn0i4lKbqtgs1W1wnTKP05aobdRkZOL97BmKia_lZvhztjPdcNsim_hWnSyT_a4rXn8681jTytMHL3HhoFcLfC/s1600/Screen+shot+2010-07-09+at+2.25.20+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 380px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnvPcQ9SzAMmncqqgFbymXxmUv_ugbGUu7uqwU7wUTksU6KDjFxKP9njFn0i4lKbqtgs1W1wnTKP05aobdRkZOL97BmKia_lZvhztjPdcNsim_hWnSyT_a4rXn8681jTytMHL3HhoFcLfC/s400/Screen+shot+2010-07-09+at+2.25.20+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491804388220253618&quot; name=&quot;BLOGGER_PHOTO_ID_5491804388220253618&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;段々面白くなってきました。このようなものが沢山有るのが解ります。もうちょっと調べるのに一番始めのインスタンスをクリックします。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKmTWUcawvXg2VkrYieOs5L6QWo7MfncIa5QDB5nksiJbt8fnH3HEbvg4KJIR-c3TqtRVEDJcYPXhXYLMIqZRUOXEtnW3e6pb_Lc6_eWJGcZRndmBHt5rM1kaqLGvkGeYCIL-kwgPhyphenhyphenWqV/s1600/Screen+shot+2010-07-09+at+2.26.53+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 380px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKmTWUcawvXg2VkrYieOs5L6QWo7MfncIa5QDB5nksiJbt8fnH3HEbvg4KJIR-c3TqtRVEDJcYPXhXYLMIqZRUOXEtnW3e6pb_Lc6_eWJGcZRndmBHt5rM1kaqLGvkGeYCIL-kwgPhyphenhyphenWqV/s400/Screen+shot+2010-07-09+at+2.26.53+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491804789419031122&quot; name=&quot;BLOGGER_PHOTO_ID_5491804789419031122&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;これは凄い。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;TimezonTransitionInfoにあてがわれたJVMクラスには三つのフィールドが有るのですね。一つはmetaClassで、Rubyのクラスを指します。もう一つはvarTableで、インスタンス変数や内部で使われている変数を格納している配列です。最後は、freezeされているか、taintされているか等、プログラムの実行時に使う様々なフラグを示すフィールドです。これらのフィールドを見ても良いですが、本稿では飛ばします。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;更に下へ行くと、もっと凄いリンクが有ります。一つはこのオブジェクトへのリファレンスのリスト。これを見ると、もう使われていない筈なのに、どうしてTimezoneTransitionInfoがGCされずにメモリに残っているのかが解ると思います。jhatでこのオブジェクトを生かす事になっているリファレンスの連鎖を、スレッドやJVMのオブジェクトにまで遡って見る事も出来ます。また、この連鎖を逆の方に辿って行く事も出来ます。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;これはjmapとjhatの機能のほんの一部に過ぎません。こんなに簡単で良いのかな、と思えるくらいに使い勝手がいいです。でも、実行中のアプリケーションを観察するにはどうすればいいでしょうか。ヒープをダンプしてオフラインで解析することで得られる情報は多いですが、オブジェクトが生成されて、そしてGCされて行く様を見たい場合も時としてあります。VisualVMを使います。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;h2&gt;&lt;br /&gt;VisualVM&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;VisualVmはNetBeansのプロファイリングのツールとして生まれました。往時のJVMについての大きな不満の一つは、同梱されいたツールがJVMを開発するエンジニアだけを対象にデザインされていた物だったという事があります。Sunには、IDEと関連するモジュールを作るという先見の明があって、これが、誰にでも使えるようなプロファイラーが自然と生まれました。これがVisualVMの起源です。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Java 6をインストールしてあるコンピュータ殆どでjvisualvmコマンドとして実行出来ます。やってみましょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrBFpm9pT_f1az8LEHw4sd4PhijPyTJQX9t7TSzl30J_rPKcoT-eFfduO00sO_2hyphenhyphenap0sPqEKqlmZbJhYILoFYg7oR_8NxTXsXofkOAB1jH3q-yXupiVKnzQlEHdzjwsre1VyXQ6cyXIDe/s1600/Screen+shot+2010-07-09+at+2.36.21+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 263px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrBFpm9pT_f1az8LEHw4sd4PhijPyTJQX9t7TSzl30J_rPKcoT-eFfduO00sO_2hyphenhyphenap0sPqEKqlmZbJhYILoFYg7oR_8NxTXsXofkOAB1jH3q-yXupiVKnzQlEHdzjwsre1VyXQ6cyXIDe/s400/Screen+shot+2010-07-09+at+2.36.21+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491807203216174802&quot; name=&quot;BLOGGER_PHOTO_ID_5491807203216174802&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;VisualVMを立ち上げると、現在実行中のJVMがjpsコマンドの場合と同じように表示されます。他のコンピュータで実行中のJVMに接続したり、ヒープダンプやコアダンプを解析したり、過去に見たメモリやCPUプロファイリングのスナップショットを見る事も出来ます。今回は、実行中のRailsアプリケーションを見てみましょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivmyMMzzEROTC0DVIzzg6DYHMmZDiup5JArf4M0aMusAsSyxmnFWzhlGTjdmNocidXEjugXyKMLZvb8fHGkNcuO89L_OT2-9qMnZ9XpqscWj5P9t3LJ1JDcoIV5TdgDeBUblXheS-c92Ev/s1600/Screen+shot+2010-07-09+at+2.38.59+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 229px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivmyMMzzEROTC0DVIzzg6DYHMmZDiup5JArf4M0aMusAsSyxmnFWzhlGTjdmNocidXEjugXyKMLZvb8fHGkNcuO89L_OT2-9qMnZ9XpqscWj5P9t3LJ1JDcoIV5TdgDeBUblXheS-c92Ev/s400/Screen+shot+2010-07-09+at+2.38.59+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491807854511040466&quot; name=&quot;BLOGGER_PHOTO_ID_5491807854511040466&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;VisualVMが実行中のプロセスに接続して、プロセスやJVMについての基本的な情報を出しました。ヒープの使用状況に興味が有りますのでMonitorのタブをクリックします。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirdQfxAJWtBHoMUsZRTsPxNLK6YS8mPSZ-Wk_djTmqoasoW1uNw-6kNrBT2LjykbF99K9svHPUXVQJBn2f52mxKss8Qe6yHzrHq-zTD6VB9iGVUOiKk7ROchkwxPZE7T7fd8AtKJmpINS8/s1600/Screen+shot+2010-07-09+at+2.40.55+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 227px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirdQfxAJWtBHoMUsZRTsPxNLK6YS8mPSZ-Wk_djTmqoasoW1uNw-6kNrBT2LjykbF99K9svHPUXVQJBn2f52mxKss8Qe6yHzrHq-zTD6VB9iGVUOiKk7ROchkwxPZE7T7fd8AtKJmpINS8/s400/Screen+shot+2010-07-09+at+2.40.55+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491808358277346098&quot; name=&quot;BLOGGER_PHOTO_ID_5491808358277346098&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;色々と有益な情報がもう入ってきました。この画面ではCPUの使用状況、ヒープの使用状況、JVMで使われているクラスの数と動きの有ったスレッドの数が表示されています。弄り始める前に一旦掃除しようと思えば、ガーベージコレクターを作動させる事も出来ます。最大の利点はjmap/jhatの二つのツールを使ってやっていた事がHeap Dumpボタンを押すだけで一気に出来る事でしょう。魅惑的でしょう？&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFOjFYMkUF9W6lMLNsdEMJAdVp517nSORQ-BUsuFYAFxUFYnGul8h5Cdm8-T-_SCGAEk0t7_3ocBpsesJqFZJYWKLaHVohqZh2lPd4CSZ_nP9v0J9_wzMmYn7etbqnzCwJfXbawgNvMtGo/s1600/Screen+shot+2010-07-09+at+2.43.36+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 228px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFOjFYMkUF9W6lMLNsdEMJAdVp517nSORQ-BUsuFYAFxUFYnGul8h5Cdm8-T-_SCGAEk0t7_3ocBpsesJqFZJYWKLaHVohqZh2lPd4CSZ_nP9v0J9_wzMmYn7etbqnzCwJfXbawgNvMtGo/s400/Screen+shot+2010-07-09+at+2.43.36+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491809057898867330&quot; name=&quot;BLOGGER_PHOTO_ID_5491809057898867330&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;初期状態ではヒープの総合的な情報が見えます。全体のサイズ、クラスの数、ガーベージコレクターのルートなどです。TimezoneTransitionInfoを探してClassesをクリックします。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZCAFvmSDg5kzgrVb_wBvYcCl3TwUhTQXez2Ggv2V6MmnMh21WSPIrlKL85As4yRKmVVRfujD_MxoERZrVwSlblL5g_o0UWznE6cEWi13PGvJulvMfNVzYk1JM_tLAfiM9kFDem-9gXV5n/s1600/Screen+shot+2010-07-09+at+2.47.52+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 196px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZCAFvmSDg5kzgrVb_wBvYcCl3TwUhTQXez2Ggv2V6MmnMh21WSPIrlKL85As4yRKmVVRfujD_MxoERZrVwSlblL5g_o0UWznE6cEWi13PGvJulvMfNVzYk1JM_tLAfiM9kFDem-9gXV5n/s400/Screen+shot+2010-07-09+at+2.47.52+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491810140647364130&quot; name=&quot;BLOGGER_PHOTO_ID_5491810140647364130&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ちょっと下の方に有りました。予想通りの数だけ在りますからダブルクリックしてもっとよく見てみましょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjixHswOeqY_-X7RdvR6RFym9NnC_YEUEAt0j9IScFfd-dFtEeDyJWNOcu0TNycDhO1MjPu5hTvWYAdWi2qMMr4Gr21CJ_nboWSdEWx9x0-BcVHzjKk_TSE1wSqm_6o62R1qE3X3CLRi4WE/s1600/Screen+shot+2010-07-09+at+2.48.41+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 176px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjixHswOeqY_-X7RdvR6RFym9NnC_YEUEAt0j9IScFfd-dFtEeDyJWNOcu0TNycDhO1MjPu5hTvWYAdWi2qMMr4Gr21CJ_nboWSdEWx9x0-BcVHzjKk_TSE1wSqm_6o62R1qE3X3CLRi4WE/s400/Screen+shot+2010-07-09+at+2.48.41+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491810376589563634&quot; name=&quot;BLOGGER_PHOTO_ID_5491810376589563634&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;jhatで既に見たのと同じ情報ですが、ここではもっと見やすくなっていますね。どれをクリックしても何か起きます。ヒープのあちこちを見て回ったり、かなりの手作業を要するような解析も簡単に出来ます。別なツールも見てみましょう。Retained Size計算機です。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;ここで見ているJVMのツールにとっては全てのオブジェクトは平等ですから、報告されている、ヒープでのRubyオブジェクトの大きさというのは全てではありません。前述の変数を格納しているテーブル、オブジェクトのインスタンス変数、そしてオブジェクトが参照しているオブジェクトなども考慮に入れなければなりません。別なオブジェクト、Gem::Versionでこれを見てみる事にします。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;スクロールしてruby.Gem.Versionクラスを探すのは面倒ですから検索しましょう。OQL ConsoleではSQLに似たクエリでヒープの中から条件に見合ったオブジェクトを探し出す事が出来ます。ruby.Gem.Versionのインスタンス全てを探します。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRYnvuxWBOzlJMga2P8VZGWj-YLyiT9BhwXPfRdktlK16WyTaYu3CIyt5FJO35qCwDnsXy4YtvbG12jSyoCCCPrhmLaMFpE9Ro8Vty6Hm2-K6Zomd4sDFzbeewUmHr_y695z5iZRjSerGD/s1600/Screen+shot+2010-07-09+at+2.53.44+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 261px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRYnvuxWBOzlJMga2P8VZGWj-YLyiT9BhwXPfRdktlK16WyTaYu3CIyt5FJO35qCwDnsXy4YtvbG12jSyoCCCPrhmLaMFpE9Ro8Vty6Hm2-K6Zomd4sDFzbeewUmHr_y695z5iZRjSerGD/s400/Screen+shot+2010-07-09+at+2.53.44+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491811793384558866&quot; name=&quot;BLOGGER_PHOTO_ID_5491811793384558866&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;クエリが実行されてGem::Versionオブジェクト全てが出てきました。これを掘り下げてどれくらいのメモリをVersionオブジェクトそれぞれがヒープにキープさせているのかを見てみましょう。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBdqSafflIvfyX_G8CLulpvdcJuCxQEFMw9NmcKwb2J4ZCBQhF0XVxKdP93O6LMGyZMpeMq3ovsQ9wwu_A1JqXnV9Pf-_GHbWzrpeflO1pzqPFpsGgb8z2KoqT1w8fHqSXbPfzkcQ1JoBw/s1600/Screen+shot+2010-07-09+at+2.55.53+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 162px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBdqSafflIvfyX_G8CLulpvdcJuCxQEFMw9NmcKwb2J4ZCBQhF0XVxKdP93O6LMGyZMpeMq3ovsQ9wwu_A1JqXnV9Pf-_GHbWzrpeflO1pzqPFpsGgb8z2KoqT1w8fHqSXbPfzkcQ1JoBw/s400/Screen+shot+2010-07-09+at+2.55.53+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491812224155538498&quot; name=&quot;BLOGGER_PHOTO_ID_5491812224155538498&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Compute Retained Sizesボタンを押すと、Instancesペーンがこのダイアログで警告を出します。これくらいではやられません。Yesをクリックします。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh27L2JBe44Ah7q2OIw4OvXzNf_vWX81ogZHpKyzVywRH5jBSHqO86r_QXLVEoTVNnQftzqrQZAsMAk9rr_s61R6YDh_ImJ87VGld_ZU8vmJGmpqKml7VzKtTr-b3KcIxGL1xtUqF31eJVC/s1600/Screen+shot+2010-07-09+at+2.57.08+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 348px; height: 106px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh27L2JBe44Ah7q2OIw4OvXzNf_vWX81ogZHpKyzVywRH5jBSHqO86r_QXLVEoTVNnQftzqrQZAsMAk9rr_s61R6YDh_ImJ87VGld_ZU8vmJGmpqKml7VzKtTr-b3KcIxGL1xtUqF31eJVC/s400/Screen+shot+2010-07-09+at+2.57.08+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491812540715047138&quot; name=&quot;BLOGGER_PHOTO_ID_5491812540715047138&quot;&gt;&lt;/a&gt;&lt;br /&gt;ちょっと休憩…&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBLGW6qYFsM5ChNKzGjgjd9huMH67NUrPzuPInWAcgktN9pU9xAJowYaljRJ6d_UTwxGVB09wjC5NiGzU-PIGEqRvvGh37KIAEYe3wQMx4Tgu71mr2aeKdFjtZpPENygofGPN29_w8Ynhs/s1600/Screen+shot+2010-07-09+at+2.59.20+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 190px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBLGW6qYFsM5ChNKzGjgjd9huMH67NUrPzuPInWAcgktN9pU9xAJowYaljRJ6d_UTwxGVB09wjC5NiGzU-PIGEqRvvGh37KIAEYe3wQMx4Tgu71mr2aeKdFjtZpPENygofGPN29_w8Ynhs/s400/Screen+shot+2010-07-09+at+2.59.20+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491859714495754226&quot; name=&quot;BLOGGER_PHOTO_ID_5491859714495754226&quot;&gt;&lt;/a&gt;&lt;br /&gt;結果が出ました。Versionオブジェクトはそれぞれ125バイトから190バイト、全部で19400バイトを消費しているようです。その殆どは変数テーブルに当てられているようです。何が入っているのでしょう。&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdco4dNc8i-DMNT1-CFOFEwbTfoBLQMExm8TOAnHKIhA5F2q75dfjUolpSf6q3QMiVPhmBX2lWprRn6fz7g42-HFGLpa40JPMI67Kc5O8SBGg4q2hAKlUMLQ3CwmdWY773NKu-IRivl9V7/s1600/Screen+shot+2010-07-09+at+3.00.31+AM.png&quot;&gt;&lt;img style=&quot;margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 77px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdco4dNc8i-DMNT1-CFOFEwbTfoBLQMExm8TOAnHKIhA5F2q75dfjUolpSf6q3QMiVPhmBX2lWprRn6fz7g42-HFGLpa40JPMI67Kc5O8SBGg4q2hAKlUMLQ3CwmdWY773NKu-IRivl9V7/s400/Screen+shot+2010-07-09+at+3.00.31+AM.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5491813418310296178&quot; name=&quot;BLOGGER_PHOTO_ID_5491813418310296178&quot;&gt;&lt;/a&gt;&lt;br /&gt;なるほど、文字列と配列のようです。ヒープに色々と探りを入れ続ける事も、JRubyやJVMのクラスの中身を見たりして、アプリケーションの本当の姿を見る事が出来ます。凄い力を手に入れました。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;h2&gt;&lt;br /&gt;あなたの番です&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;勿論これは氷山の一角です。例えば、Eclipse Memory Analysis Toolにはメモリリークを探知する機能があります。VisualVMとNetBeansにはアロケーショントレーシングという、アプリケーションコードのどこでオブジェクトが生成されているのかを見せる機能もあります。GCの動向を見せるツールも数多く有り、中には稼働中のヒープを弄ってオブジェクトを操作出来るものすらあります。あったらいいな、と思うような機能は何かしらのツールに備わっている、と言えるくらいです。JRubyを使えばそのようなツール全てを何の手を加える事もなく使えるのです。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;ここで述べたツールは全てJRuby 1.5.1で使えますが、Rubyクラスに上手に対応するJVMクラスはありません。それにはソースコードからビルドするか、1.6.0.devバージョンをダウンロードするか、或いは1.6.0のリリースを待つかする必要があります。これらを含め、どんなツールを使っているか、是非報せて下さい。このブログでも取り上げたいと思います。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;近いうちに、他のツールと、CPUプロファイリングについても取り上げます。それまでは、JRubyを使えばこのような素晴らしいツールが使えるのだと言う事を覚えておいて下さい。&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/4926022619220969698/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/07/jruby.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/4926022619220969698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/4926022619220969698'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/07/jruby.html' title='JRubyのメモリを観察するには'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-ArUhvLvbstNnje2F8Ui4fEZEqR_ydDC7Kaq947YzIHVfjQlADuhLpEb3lA-E2fGlVieLXju9uxH4URcKeXV2bkktzZlkI4_rYM9Fg6dG62tkpEqFL5Dx1qOt5yxUEOyJ64flDQQSYD0T/s72-c/Screen+shot+2010-07-09+at+2.15.35+AM.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-299097196928084051</id><published>2010-06-17T23:18:00.001-05:00</published><updated>2010-06-17T23:18:42.200-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>今のJVMに欠けている物</title><content type='html'>&lt;a href=&quot;http://blog.headius.com/2010/06/my-short-list-of-key-missing-jvm.html&quot;&gt;原文&lt;/a&gt;: チャールズ＝オリバー＝ナター&lt;br /&gt;&lt;p&gt;今日ツイッターで、「JVM及びJDKが、あらゆるプログラミングにおいて真にイケてるプラットフォームになる為には未だ幾つかの欠陥が有る」と呟きました。沢山の人から「もっと詳しく」とせっつかれたので、ここに短く書き起こしておきます。勿論、これで全部という訳ではないのでしょうが、今日思いついたのはこれだけです。&lt;br /&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;h2&gt;ゼロから起動する際のパフォーマンス&lt;/h2&gt;&lt;p&gt;現存するJVMの起動はかなり速いですが、Java 7でのHotSpot（訳注：Sun及びオラクルのJVM）にはこれをより良くする為の改良が盛り込まれています。普通、こういった改良は、バイトコードを予め検証したり（或いは検証の為のヒントを与えたり）、クラスデータを幾つかのプロセスで共有したり、在り来たりではありますがプログラムのロード時間やリンク時間を短縮する工夫を凝らす事で成し遂げられます。ところが、多くのアプリケーションにしてみれば、このような改良は、起動時間を長引かせる最大の原因（ゼロから起動する際のパフォーマンス）には余り効果がありません。JVMはJITコンパイルした結果をセーブしないので、起動する際には常にゼロからのスタートを余儀なくされます。その時、コンパイルするに至る迄はバイトコードをインタープリタで走らせるのです。インタープリタの無いJVMでさえ、一番初めに掛かる、それほど最適化されていないアセンブリコードへのコンパイルにはかなりの時間を要します（コマンドラインでJRockit（オラクル及びBEAのJVM）やJ9(IBMのJVM）をいじってみて下さい）。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;改善の為の提案は今までにもなされていますが、どれも一筋縄では行きません。&lt;br /&gt;    &lt;dl&gt;&lt;li&gt;&lt;dt&gt;コンパイルする過程の分割&lt;/dt&gt;&lt;dd&gt;初めのコンパイルは最速で、最適化を行わないコンパイラを使い、後から適当なプロファイリングを行いながら最適化を行う。HotSpotのJava 7リリースではこのようなコンパイラが装備されるかも知れませんが、この開発を妨げるような問題が幾つか有りました。&lt;/dd&gt;&lt;/li&gt;&lt;li&gt;&lt;dt&gt;コンパイルした結果や最適化した結果を何らかの形で保存する&lt;/dt&gt;&lt;dd&gt;理論的には可能ですが、これを深く追求すればするほど保存するのは難しくなっていきます。メモリ内で行われる最適化やコンパイルの結果は、普通メモリのレイアウトに依存しています。これをディスクに保存すると、ロードする際、以前と違う物（メモリアドレスやクラスアイデンティティ等）を消してしまう必要が有ります。.NETでは、凡、静的コンパイルに限られてはいるものの、これが可能です。これが妥協点という事でしょうか。&lt;/dd&gt;&lt;/li&gt;&lt;li&gt;&lt;dt&gt;JVMを常に走らせておいて、それに新しい仕事を与える。&lt;/dt&gt;&lt;dd&gt;JRubyではnailgunというライブラリを用いてこれを実現していますが、問題点が幾つか有ります。第一に、JVMの状態（システムプロパティやメモリ消費量）に不都合が生じる場合が有ります。第二に、死なないスレッドが発生した場合にそれを終了させる事が出来ないので、長い間走っていると、このような「死に損ない」のスレッドが溜まって行きます。そして第三に、コンソールで走っている訳では有りませんから、普段コンソールで当たり前にやっているような事が出来ません。&lt;/dd&gt;&lt;/li&gt;&lt;/dl&gt;&lt;/p&gt;&lt;p&gt;これが、JRubyが直面する解決出来ない最大の問題であり、弁明を必要とする最大の問題です。JRubyは速く、時としてとても速く、日に日に速くなっていますが、初めの五秒はそんなに速くないので、余り良いとは言えない第一印象を与えることになるのです。&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;コンソールとターミナルのサポートを強化&lt;/h2&gt;&lt;p&gt;標準でJVMに装備されているIOストリームが色々な面で役に立たないと嘆いているブログは枚挙に暇が有りません。例えば、selectを使えないというのがありますが、JRubyにはこれが原因で直せないバグが幾つか有ります。また、サブプロセスに渡す事が出来ない、というのも有りますが、これはIOライブラリの欠陥よりはプロセス起動の為のAPIに拠る所が多いと言えるでしょう。ターミナル関係の機能はJava APIには悉く欠落しているので、ラインエディットの機能を備える為だけにjlineみたいなライブラリを取り入れざるを得ない事になるのです。もしJDKがターミナルとプロセスを上手く扱えるAPIを標準で備えると、こうした余計な手間暇を掛ける必要が無くなってしまいます。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;未だ望みは有ります。Java 7に取り入れられる予定のNIO2ではプロセス起動の為のAPI（標準IOストリームを継承する事も可能）や、select可能な様々なチャンネル等の多くの機能が盛り込まれています。これで充分だといいですね。&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;壊れたAPIを直す&lt;/h2&gt;&lt;p&gt;JDBCは欠陥品です。何故かと言うと、ドライバーをハードリファレンスを含んだマップに登録しなければならず、登録を行ったクラスローダーから登録削除をしなければメモリリークしてしまうからです。と言う事は、ウェブアプリやEEアプリケーションからJDBCをロードすると、ドライバーがアプリケーションへのリファレンスを持ち、且つ上に述べたマップがドライバーへのリファレンスを持つので、アプリケーション全体がメモリに残る事になります。これがアプリケーションサーバがアプリケーションをundeployした後でもメモリリークを起こす最大の理由です。JRubyの立場から言うと、これも直す事が出来ないバグです。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;オブジェクトのシリアル化も壊れています。何故かと言うと、クラスローダーを獲得し、オブジェクトのフィールドをリフレクションによりアクセスし（リフレクションを使ってフィールドにアクセスするならば、可能ならばいっそのことカプセル化等は無視してしまえばいい）、そしてオブジェクトのインスタンスを適切に初期化する事なく生成する為に有りとあらゆるトリックを使っているからです。これを使う為には、引数を何も取らないコンストラクタを用意したり、コンストラクタ以外でも初期化が可能なようにfinal修飾子を外したりしなければならず、万が一にもデフォルトで用意されているシリアライザを使おうものなら、その遅さは天誅が下るほどです。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;リフレクションが遅すぎるのに、これをどうする事も出来ないというのもあります。リフレクションを通したメソッドを呼び出しを何層にも渡って行う羽目になるだけではなく、引数のリストと数値関係をボックス化しなければならず、加えて例外を扱う為にこれ等全てをラッパーに包む必要が有る、と言った具合です。invokedynamicに伴って、メソッドへのアクセスが高速な直のポインターであるメソッドハンドルが装備されます。これは当の昔に加えられて然るべきフィーチャでしたが、幸いな事にJava 7でこれが現実のものとなります。それ迄は、JRuby等のプロジェクトはリフレクションに掛かるコストを負担するか、メソッドハンドルを手作業で生成するしかありません。実際、JRubyでは両方やっています。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;正規表現もいただけません。簡単な選択を用いるだけで、大きなインプットに出くわした時Javaスタックが崩壊してしまうほどです。現在の、Sunによって産み出された正規表現は、選択等に再帰を用いているのでインプットが大きいと簡単に壊れてしまいます。JRubyではこの酷い問題に対処する為、我々自身の手で行ったもの二度を含めて、何と四度も正規表現エンジンの実装を行いました。ユーザの為には私たちは血の滲むような努力をしています。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;他にも例はまだまだあります。それはJava 1.0から手直しの入っていない遺物あったり、（老いたAPIは死なず。ただ軽視されゆくのみ…あるいは完全無視されるのみ。）実際には複数のJVMプロセスがアプリケーションを一つずつ又は多くても二三個走らせているのが効率的であるのに、巨大な一枚岩の様なサーバが何十ものアプリケーションを取り扱うのが良いという姿勢の遺物もあります。加えて一枚岩な環境では、アンデプロイの際にメモリリークを起こしたり、プロセスを隔離していれば起こらない、基本的なリソースの奪い合いが起きるなどの問題を抱えています。このようにまずいAPIを本腰を入れて手直しをするのは価値ある事だと思います。&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;ネイティブライブラリとPOSIX機能の強化&lt;/h2&gt;&lt;p&gt;Java 6の時点ですらシンボリックリンクを扱う事が出来ませんし、ファイルのアクセス許可設定も限られたものです。プロセスを新たに起動させるAPIはとても酷い。全てのチャンネルでselect出来ない。出来るのはソケットだけ。ネイティブライブラリを使う為には、JNAやJFFI等の、ネイティブライブラリを動的にロード及びバインドする素晴らしいライブラリが有るにも拘わらず、JNIのコードを書かなければなりません。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;POSIXに似たフィーチャが欠けているのは今では言語道断です。JDKに見られるシステムレベルのAPIの殆どは、Windows 95辺りの最低限のレベルに合わせたものです。最近のオペレーティングシステムではPOSIXのAPIの殆どを実装しているというのに。NIO2により、かなり改善されますが、POSIXの一部が対応されないのはほぼ確実です。対応されなかったPOSIX APIにJava APIを完全に合わせるには人手が足りないとか、システムに依存し過ぎのAPIである、等の理由が考えられます。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;ネイティブライブラリをロードする問題についても、これが当の昔にJDKの一部になっていて当然であると言えます。「純粋なJavaを!」と声高に叫ぶ人は多いと思います。私も叫ぶでしょう。しかし、Javaのライブラリには機能が備わっていないとか、外部プロセスを介していたのでは容量向上に期待出来ない場合はあります。このような場合、ネイティブライブラリを使わざるを得ません。ところが、これをJavaプラットフォームでやろうとすると、入門者には中々手も足も出るような代物では有りません。ネイティブコードをいつ呼び出すか、自分たちで選べるようにするためにも、JNAやJFFI、又はこれに似た物をJDKに入れて欲しいものです。&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;決め台詞&lt;/h2&gt;&lt;p&gt;ここまでに挙げた様々な問題点の多くは、JRubyでは多大な代償を払って、解決或いは何らかの方法で対処してきました。他のどのプロジェクトよりもJVMやJDKの欠点に対処してきたと言っても過言ではないでしょう。起動時間の短縮の為にあらゆる手段を尽くしました。Cのコードを一行も書く事なくネイティブライブラリにバインド出来るように、華麗かつ堅実なライブラリを同梱しています。コンパイルの際、また実行時に多くのコードを生成して、リフレクションをそれほど使わずに済むような工夫もしています。十数個のOSでPOSIXにネイティブに対応しています。Marcin Mielzynski氏が鬼車をJavaに移植しました。外部プロセスの呼び出しがRubyユーザの思惑通りになるように考えられるトリックは全て使いました。云々。&lt;br /&gt;&lt;/p&gt;&lt;p&gt;でも、このやり方では長くやって行く事は出来ません。今まで上手くやってきたとは言え、JVMやJDKにいつまでも継接ぎを当てて行く訳には行きません。願わくば、この記事が世界中のJVMとJDKの開発者への警鐘となりますように。Javaプラットフォームが、サーバのみ、巨大アプリのみ、継続アプリのみ、ターミナル無しの世界になってしまわないようにするために、これらの問題点を解決して下さい。いつでも協力します。:-)&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/299097196928084051/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/06/jvm.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/299097196928084051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/299097196928084051'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/06/jvm.html' title='今のJVMに欠けている物'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-618041604486425070</id><published>2010-06-15T22:19:00.001-05:00</published><updated>2010-06-15T22:45:27.574-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="JVM"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRubyのパフォーマンスの更なる向上を目指して</title><content type='html'>&lt;a href=&quot;http://blog.headius.com/2010/05/kicking-jruby-performance-up-notch.html&quot;&gt;原文&lt;/a&gt;: チャールズ＝オリバー＝ナター&lt;br /&gt;&lt;p&gt;JVM上でJRubyが動く事の利点は折りに触れて述べてきました。JRubyのパフォーマンス数値はそこそこの結果を出しているのですが、多くの人々の期待に反して「抜群に素晴らしい」というものではありませんでした。詰まる所、他のRuby言語の実装に較べて良い結果を出したとしても、静的な型システムを用いる他のJVM言語には敵わないのでした。&lt;/p&gt;&lt;p&gt;しかし、それは今までの話し。&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;最近、JRubyの実行時に得られる情報に基づいた最適化をあれこれと試し始めました。ご存知の通り、JRubyは、Ruby言語の構造木をJVMのバイトコードにコンパイルするJITを搭載しています。その一方で、JITを使った他のシステムとは異なり、JRubyは最終的に良い結果をもたらすような情報をプログラムの作動時点で集めることはしなかったのです。今までにやっていた最適化と言えば、AOTコンパイラで安全に出来るような静的な最適化、そして最終的には、実行前にすべてをコンパイルすることによる起動コストを減らすための、遅延コンパイルJITモード（訳注:現在のデフォルトJITモード。以前はJITなしか、最初にすべての静的最適化を行うか、の2択だった）を追加することでした。&lt;/p&gt;&lt;p&gt;これは実用的な判断でした。JVMは沢山のことをやってくれるので、JRubyが実装しているような未熟なコンパイラと限られた静的な最適化でも、パフォーマンスの向上は見込めます。この為、JRubyのパフォーマンスは凡その用途には極めて満足の行くものでした。18ヶ月前のバージョン1.1.6以来、実行スピードの向上については野放しといったような具合でした。この間中はユーザからの要望を優先させていました。Javaとのより良い統合性、Rubyとの互換性の向上、メモリ消費（稀にリーク）の改善、jruby-rackやactiverecord-jdbc等周辺ライブラリの充実、そしてシステム一般の安定化などです。ユーザにパフォーマンスは？と訊くと、「あれば良い」という意見が一般的で、特に問題があるという意見は極々稀でした。JRubyのパフォーマンスは極めて満足の行くものだったと言えるでしょう。&lt;/p&gt;&lt;p&gt;とは言うものの、最近になって幾つかの避けられない真実に直面せざるを得なくなってきました。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;幾ら速くても速すぎる事はないし、スピードが上がっていかなければ相対的に遅くなっている印象を与えてしまう。&lt;/li&gt;&lt;li&gt;RubyのプログラムをCやJava並に速く動かしたいという要望は有るので、もし可能ならばそれを実現させるべき。&lt;/li&gt;&lt;li&gt;JRubyユーザは（当然の事ですが）Rubyでプログラムを書きたいので、出来るだけRubyで書けるようにするべき。その際、パフォーマンスで犠牲を払わずに済むようにするべき。&lt;/li&gt;&lt;li&gt;パフォーマンス向上にはとても時間が掛かるけれども、それが達成出来た時の悦びは一塩。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;そう言った訳で、JRuby 1.6の俎上に上がっている項目に加えて、私はコンパイラをいじる事を決意しました。&lt;/p&gt;&lt;p&gt;取り掛かって間も無いので、その辺は了承して下さい。&lt;/p&gt;&lt;h1&gt;JRubyのコールサイトについて&lt;/h1&gt;&lt;p&gt;Rubyのコードで動的にメソッドが呼び出される場所それぞれに、JRubyはコールサイトと呼ばれるものを組み込みます。他のVMでは単にこの呼び出しが起こる場所の事をコールサイトと呼ぶ場合もありますが、JRubyではコールサイトは&lt;code&gt;org.jruby.runtime.CallSite&lt;/code&gt;の実装を伴います。次のコードを例に挙げます。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;def fib(a)&lt;br /&gt;  if a &amp;lt; 2&lt;br /&gt;    a&lt;br /&gt;  else&lt;br /&gt;    fib(a - 1) + fib(a - 2)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;このコードには全部で六つのコールサイトがあります。&lt;code&gt;a&amp;lt;2&lt;/code&gt;の中の&lt;code&gt;&amp;lt;&lt;/code&gt;、&lt;code&gt;a-1&lt;/code&gt;と&lt;code&gt;a-2&lt;/code&gt;にある二つの&lt;code&gt;-&lt;/code&gt;、二つの&lt;code&gt;fib&lt;/code&gt;メソッドの呼び出し、そして最後に&lt;code&gt;fib(a-1)+fib(a-2)&lt;/code&gt;に見られる&lt;code&gt;+&lt;/code&gt;です。余りよく考えずに動的なメソッド呼び出しをしようとする方法としては、それぞれのオブジェクトに問題のメソッドが有るかどうかをその度に確認して、あればそれを実行するというのが考えられます。（これは最もてぬきなリフレクションコードがやるようなやり方です。）他の動的な言語のVMの例に外れる事なく、JRubyでもコールサイトのキャッシュを用いる事でメソッドの有無の確認に掛かる費用を軽減しています。実装の立場から言うと、キャッシュされる&lt;code&gt;CallSite&lt;/code&gt;は全て&lt;code&gt;org.jruby.runtime.callsite.CachingCallSite&lt;/code&gt;のインスタンスであるという事です。簡単でしょう？&lt;/p&gt;&lt;p&gt;ランタイムで集める事の出来る情報を利用する最も簡単な方法は、このようにキャッシュされたコールサイトをヒントにして、それぞれのコールサイトでどのメソッドが呼び出されるのかを知ることです。上に挙げた&lt;code&gt;+&lt;/code&gt;をの場合を見てみましょう。ここで、&lt;code&gt;+&lt;/code&gt;メソッドはその都度Fixnumオブジェクトに対して呼び出され、ここでは&lt;code&gt;fib&lt;/code&gt;の値は&lt;code&gt;Bignum&lt;/code&gt;へと溢れ出るくらい大きくならないとして、&lt;code&gt;Float&lt;/code&gt;とも無関係という事にします。JRubyでは&lt;code&gt;Fixnum&lt;/code&gt;オブジェクトは&lt;code&gt;org.jruby.RubyFixnum&lt;/code&gt;というクラスで実装されていて、&lt;code&gt;+&lt;/code&gt;メソッドは&lt;code&gt;RubyFixnum.op_plus&lt;/code&gt;として実装されています。こんな具合です。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;@JRubyMethod(name = &quot;+&quot;)&lt;br /&gt;public IRubyObject op_plus(ThreadContext context, IRubyObject other) {&lt;br /&gt;    if (other instanceof RubyFixnum) {&lt;br /&gt;        return addFixnum(context, (RubyFixnum)other);&lt;br /&gt;    }&lt;br /&gt;    return addOther(context, other);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;addFixnum&lt;/code&gt;の詳細は宿題という事にします。&lt;/p&gt;&lt;p&gt;ここで&lt;code&gt;@JRubyMethod(name = &quot;+&quot;)&lt;/code&gt;というアノテーションがある事に注意して下さい。JRubyで実装されているRubyのコアクラスのメソッドには全てこのようなアノテーションが付随していて、引数の数、Ruby側から見たメソッドの名前（ここで見る&lt;code&gt;+&lt;/code&gt;はJavaでは許されないメソッドの名前です）等、メソッド呼び出しの詳細を指定します。また、このメソッドは二つの引数を取る事に注目して下さい。&lt;code&gt;ThreadContext&lt;/code&gt;（このメソッドを実行しているスレッド特有のランタイムの情報）オブジェクトと、今まさに足されようとしている&lt;code&gt;other&lt;/code&gt;（引数）です。&lt;/p&gt;&lt;p&gt;JRubyをコンパイルする際、全てのソースファイルを読み込んで&lt;code&gt;JRubyMethod&lt;/code&gt;のアノテーションを抽出し、コアクラスのメソッド一つ一つにインボーカを生成します。このインボーカは&lt;code&gt;org.jruby.internal.runtime.methods.DynamicMethod&lt;/code&gt;クラスのインスタンスで、メソッドについての詳細及び呼び出しの際のシグネチャ等の情報を含んでいます。このようにインボーカを生成する理由は簡単です。JVMの殆どは、多数のコードパスを持つコードはインライン展開しないので、たった一つのインボーカで全てのメソッドに対処しようとすると、インライン展開は全く行われない事になるのです。ここまでの話をまとめてみましょう。プログラムの実行の際、Rubyのコードにあるメソッド一つ一つに&lt;code&gt;CachingCallSite&lt;/code&gt;インスタンスがあり、例えば&lt;code&gt;+&lt;/code&gt;メソッドが初めて呼び出された時これに対応するメソッドのオブジェクトを取ってきて、これ以降の呼び出しの為にキャッシュします。キャッシュされたメソッドは&lt;code&gt;DynamicMethod&lt;/code&gt;のサブクラスで、最終的にどのように&lt;code&gt;RubyFixnum.op_plus&lt;/code&gt;メソッドを呼び出して、返り値をどう扱えばいいのかも知っているのです。至極簡単です！&lt;/p&gt;&lt;h1&gt;初めの一歩&lt;/h1&gt;&lt;p&gt;暫くプログラムを走らせていると、どのメソッドが呼び出されるのか大体見当がつきます。私の手元で試しているコードではこの点に漸く着目しています。そして、どのメソッドが呼び出されるのか事前に判っているのなら、前提が満たされる限り呼び出しは動的でなくて構いません。（ここで言う前提とは、例えば「このメソッドは常にFixnumについて呼び出される」とか「これのメソッドは&quot;+&quot;のコア実装である」といったものです。）つまり、JRubyはJVMバイトコードへのコンパイルを遅らせる事で、動的なメソッドの呼び出しを静的な呼び出しへと換える事が出来るかも知れない、と言う事です。&lt;/p&gt;&lt;p&gt;このプロセスは実はとても簡単です。私もつい二日前に始めたばかりですので、この過程を追って見てみましょう。&lt;/p&gt;&lt;h1&gt;第一段階：動的呼び出しを静的呼び出しに置き換える&lt;/h1&gt;&lt;p&gt;まず初めに必要なのは、生成されたメソッドに直接呼び出しを可能にするだけの情報を持たせることです。もっと詳しく言うと、どのJavaクラスをターゲットにしているのか（&lt;code&gt;+&lt;/code&gt;の例で言うとターゲットは&lt;code&gt;RubyFixnum&lt;/code&gt;です）、Javaメソッドとしての名前（&lt;code&gt;op_plus&lt;/code&gt;）、返り値及び引数の数と型（&lt;code&gt;IRubyObject&lt;/code&gt;を返し、引数は&lt;code&gt;ThreadContext&lt;/code&gt;と&lt;code&gt;IRubyObject&lt;/code&gt;）、そしてメソッドがstatic宣言されているかどうか（モジュールメソッドの殆どはそうですが、&lt;code&gt;op_plus&lt;/code&gt;はそうではありません）。これらの情報を一つに纏め上げて&lt;code&gt;NativeCall&lt;/code&gt;という型に入れ込む事にし、これをこれを静的呼び出しが可能かもしれないすべてのインボーカに割り当てます。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;public static class NativeCall {&lt;br /&gt;        private final Class nativeTarget;&lt;br /&gt;        private final String nativeName;&lt;br /&gt;        private final Class nativeReturn;&lt;br /&gt;        private final Class[] nativeSignature;&lt;br /&gt;        private final boolean statik;&lt;br /&gt;        ...&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;コンパイラにも似通ったロジックを付けました。動的な呼び出しをコンパイルする際、まずコールサイトが何らかのメソッドを既にキャッシュしているかを調べます。もしキャッシュしているのならば、そのメソッドに相応の&lt;code&gt;NativeCall&lt;/code&gt;が有るかどうかを確認します。有るのなら、いつもの様に動的にメソッドの呼び出しをするのではなく、JVMのごく普通のメソッドのようにコンパイルします。こうすると、今まで&lt;/p&gt;&lt;pre&gt;&lt;code&gt;INVOKEVIRTUAL org/jruby/runtime/CallSite.call&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;だったものが&lt;/p&gt;&lt;pre&gt;&lt;code&gt;INVOKEVIRTUAL org/jruby/RubyFixnum.op_plus&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;となり、&quot;+&quot;メソッドの呼び出しはRubyFixnumクラスを扱うJavaコードを書いているのと実質同じになります。&lt;/p&gt;&lt;p&gt;これで第一段階（コンパイラに、ここまでに見たような動的なメソッド呼び出しを認識させ、静的呼び出しにする）は終了です。この試験的な手法はコアクラスのメソッドの殆どに今すぐ使えますし、あらゆる呼び出しに使えるようにするのは難しくないでしょう。&lt;/p&gt;&lt;p&gt;鋭いVM実装者は既にお気付きかも知れませんが、後に実際は別のメソッドを呼び出す必要がある時のために備えるためのガードの挿入や事前のテストに、ここまでは言及していません。これは意図したものです。この話は後で触れます。&lt;/p&gt;&lt;h1&gt;第二段階:Fixnumの使用を抑える&lt;/h1&gt;&lt;p&gt;次に私がやったのは、ボックス化されたRubyFixnumではなくプリミティブ型の使用を許す事でした。JRubyではRubyFixnumは常に64ビットlongですが、メソッドの呼び出しの時にはIRubyObjectを使わなければならず、動的メソッドの呼び出しの際にはRubyFixnumオブジェクトを新たに作り出す必要が有ります。この時に作り出されるオブジェクトはとても小さく、直ぐに要らなくなるのでGCへの影響は問題では有りません。でもアロケートする時の速度には勿論影響があります。RubyFixnum一つ一つにメモリを確保しなければならず、その為にメモリ帯域幅を食い潰してしまいます。&lt;/p&gt;&lt;p&gt;このようなオブジェクトの割当を無くしたり軽減させる手段としては、スタックアロケーション、値型、即値、エスケープ解析等があります。このうち現存するJVMで使えるものはエスケープ解析だけで、しかも非常に扱い辛いです。と言うのも、あるオブジェクトを利用するすべてのパスがインライン展開されていなければならず、さもなくばそのオブジェクトを（エスケープ解析によってはにより）省略できません。&lt;/p&gt;&lt;p&gt;そこで、JVMへの負担を減らす為、ボックス化されたlongまたはdouble（Rubyで言うところのRubyFixnum及びRubyFloat）を一つだけ渡しているのが確実な場所に、プリミティブのlongまたはdoubleを受け取る呼び出し先を追加します。つまり、第二段階と言うのは、このようなメソッドをRubyFixnumについて幾つか実装する事でした。&lt;code&gt;op_plus&lt;/code&gt;を&lt;code&gt;long&lt;/code&gt;に対応させたのがこれです。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;public IRubyObject op_plus(ThreadContext context, long other) {&lt;br /&gt;    return addFixnum(context, other);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ここまででは、或るオブジェクトが常にFixnumであるという事を証明するような手段は未実装なので、コンパイラには今の所100とか12.5といったようなリテラルを引数にしてメソッドの呼び出しをしているようにしか見えません。幸運にも、上の&lt;code&gt;fib&lt;/code&gt;の例では丁度そのような場面が三つありました。一つは&lt;code&gt;&amp;lt;&lt;/code&gt;、そしてもう二つは&lt;code&gt;-&lt;/code&gt;です。「&lt;em&gt;どの&lt;/em&gt;メソッドが場面場面で実際に使われているか」という知識と「&lt;code&gt;RubyFixnum&lt;/code&gt;を介さずにメソッドを&lt;em&gt;どう&lt;/em&gt;呼び出すか」とを合わせる事により、実際のバイトコードはこのように簡単になります。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;INVOKEVIRTUAL org/jruby/RubyFixnum.op_minus (Lorg/jruby/runtime/ThreadContext;J)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;（この表記に不慣れな読者の為に添え書きしておきますと、引数の最後の&lt;code&gt;J&lt;/code&gt;は、この呼び出しが第二引数でプリミティブである&lt;code&gt;long&lt;/code&gt;を要求している事を示しています。）&lt;/p&gt;&lt;p&gt;これでメソッド呼び出しを効率良く行う為の準備が出来ました。勿論、この例はとても単純ですが、RubyからJavaで書かれた恣意のコードの呼び出しに使える可能性を示しています。RubyからJavaのコードを呼び出す時、独自の複雑なマルチメソッド呼び出しロジック&lt;em&gt;及び&lt;/em&gt;何層もあるJavaのリフレクションAPIを経る事なく、直接Javaのコードを呼ぶ事が出来るという事です。中間に有るコードがなければJVMはJavaのコードをRubyのコードの中にインライン展開する事が出来、全体を最適化するのです。ワクワクしてきたでしょう？&lt;/p&gt;&lt;h1&gt;第三段階:極小最適化をちょこちょこと&lt;/h1&gt;&lt;p&gt;さて、&lt;code&gt;fib&lt;/code&gt;には後二つ厄介なメソッド呼び出しが残っています。&lt;code&gt;fib&lt;/code&gt;の再帰呼び出しです。これを上手く片付けるやり方としては、既にjitコンパイルされているRubyコードから呼び出される、未だjitコンパイルされていないRubyコードが存在することをコンパイラに教えると言う事が考えられます。例えば、そうしたメソッドを強制的にコンパイルさせて、そのコンパイルされたメソッドから呼び出されるメソッドをもコンパイルさせて…という風にやっていって、ホットなメソッドから順々に或る程度の閾値まで最適化を行っていく訳です。「例え」とは言いましたが、これが多分実装になると思います。JRubyでRubyメソッドをjitコンパイルするのは容易い事なので、これをコンパイラに実装するには数分で充分です。でも、木曜日から考え続けて、もう一捻りやる事にしました。&lt;/p&gt;&lt;p&gt;コンパイラに「入れ知恵」する替わりに、非常に簡単な単一の最適化の方法を取り入れる事にしました。つまり自己再帰を検出し、その場合に限って最適化をする訳です。JRubyの場合で言うと、&lt;code&gt;fib&lt;/code&gt;に相応する&lt;code&gt;CachingCallSite&lt;/code&gt;オブジェクトが、今まさにコンパイルしようとしている同じ&lt;code&gt;fib&lt;/code&gt;メソッドを呼び出していることを割り出すという事。このメソッドを動的メソッド呼び出しのパイプラインに流し込むのではなく、直接の再帰呼び出しに換えてしまう訳です。丁度、コアメソッドである&lt;code&gt;&amp;lt;&lt;/code&gt;と&lt;code&gt;-&lt;/code&gt;と&lt;code&gt;+&lt;/code&gt;を換えた様に、です。バイトコードレベルでは&lt;code&gt;fib&lt;/code&gt;の呼び出しはこのようになります。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;INVOKESTATIC ruby/jit/fib_ruby_B52DB2843EB6D56226F26C559F5510210E9E330D.__file__&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ここで、B52DB28云々という所は&lt;code&gt;fib&lt;/code&gt;メソッドのSHA1ハッシュ、そして&lt;code&gt;__file__&lt;/code&gt;というのはjitコンパイルされたメソッドのデフォルトのエントリーポイントです。&lt;/p&gt;&lt;h1&gt;ここだけの話ですが…&lt;/h1&gt;&lt;p&gt;実験的なコードには付き物の話ですが、ここでは、互換性を多少犠牲にすればどれくらいのパフォーマンス向上が謀れるかを示しています。&lt;br /&gt;ですから、ここで挙げた最適化の手段には幾つかの注意点が有ります。&lt;/p&gt;&lt;p&gt;まず、インボーカを素通りするのでRuby独自のバックトレース情報（現在のメソッド名、ファイル名、行番号など）をヒープで保持する事が無くなり、Rubyのバックトレースが滅茶苦茶になってしまう、という点。この点はJRubyが、JavaとRuby両方のバックトレース情報を保持する為にパフォーマンス劣化を余儀なくされる所です。JavaのバックトレースでRubyの関係のある情報を保持出来るようにするか、またはRubyのバックトレースをJavaのバックトレース情報から掘り出す（現存する&lt;code&gt;--fast&lt;/code&gt;オプションでこれは可能です）ようにするにはまだまだ課題は山積しています。&lt;/p&gt;&lt;p&gt;次に、ここでは&lt;code&gt;backref&lt;/code&gt;や&lt;code&gt;lastline&lt;/code&gt;に当たるもの（&lt;code&gt;$~&lt;/code&gt;と&lt;code&gt;$_&lt;/code&gt;に相当するもの）を扱う為の情報を管理していません。つまり、正規表現や行単位の処理などでは機能の低下が有る事になります。（とは言うものの、これらの値を使うのは推奨されていないので、この事は余り苦にならないかも知れません。）スレッド固有のスタックを上手く使う（つまり、このような変数を扱うかも知れないメソッドに出くわした時にだけスタックに変数を押し込む）事で、この機能は取り戻せるでしょう。理想的には、或るコールサイトが&lt;code&gt;$~&lt;/code&gt;や&lt;code&gt;$_&lt;/code&gt;を読み書きするかは判るので、実行時にプロファイリングする事で賢くこういった判断を行える筈です。&lt;/p&gt;&lt;p&gt;最後に、直接呼び出しするか、普通の動的なメソッド呼び出しをするかで枝分かれする所にガードを置いていません。これは実験を素早く進める為に執った実利的な決断です…と同時に興味深い問題を提示するものでも有ります。もしも、このメソッドが見得る全ての型とメソッドを見てしまったと解るのならどうでしょうか。「死ぬほど最適化して」と言い放つ事が出来れば、そして、実際JVMがそうしていると知ることが出来ればと思いませんか。個人的にはそのようなガード（理想的には、パフォーマンスに余り影響のない簡単な「メソッドID」の照合）無しにJRubyがリリースされるとは到底思えませんが、そうした「静的化」による最適化は、ユーザの意思でスイッチを入れることが出来るようになると思います。更に、もしもJRubyの実装のより多くをRubyで書かれたコードに移行する事になれば、こうした「完全な」最適化を利用するであろうと思われます。&lt;/p&gt;&lt;p&gt;さて、こうした注意点に留意しながら実測値を見てみる事にしましょう。&lt;/p&gt;&lt;h1&gt;それでは、フィボナッチ数の計算のためにJRubyを利用されている皆様以外には無意味な数値をご覧にいれましょう。&lt;/h1&gt;&lt;p&gt;&lt;code&gt;fib&lt;/code&gt;メソッドはベンチマークにおいて恐ろしく乱用されています。ほとんどの呼び出しが少なくとも2つの再帰的呼び出しと、数値演算によるその他いくつかの呼び出しを生じさせるため、主にメソッド呼び出しのベンチマークになります。またJRubyでは処理時間の大半が、Fixnumオブジェクトの生成か、呼び出し毎の実行時データ構造の更新に取られるため、このベンチマークは、メモリ割り当て率またはメモリ帯域幅のベンチマークを兼ねることになります。&lt;/p&gt;&lt;p&gt;しかしベンチマークとしては結果が解り易いので、今一度これを乱用することにします。どうか、以下の数値は、互いの数値を比較するのでない限り無意味であることを肝に銘じておいてください。JRubyは未だに、即値や値型での実装よりも遙かに多くのオブジェクトを生成しており、その為、JVMはこのベンチマークの一部分を最適化し過ぎていると思われます。しかしもちろん、そこがポイントの一つです。我々はJVMを加速させ、潜在的に不必要な計算の排除を実現しようとしており、また実行時コンパイルの改良に実行時データを利用することで、それらが可能になってきています。&lt;/p&gt;&lt;p&gt;使うのは、2.66GHzのCore 2 Duoプロセッサを搭載したMacBook Pro。OS XとJava 6 (1.6.0_20) 64-bit Server VMで動作する、JRuby 1.6.dev (masterに私的なハックを入れたもの)です。&lt;/p&gt;&lt;p&gt;まず、フル機能のRubyバックトレースと、動的呼び出しでの、基本的なJRubyでの&lt;code&gt;fib&lt;/code&gt;測定値です。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;0.357000   0.000000   0.357000 (  0.290000)&lt;br /&gt;0.176000   0.000000   0.176000 (  0.176000)&lt;br /&gt;0.174000   0.000000   0.174000 (  0.174000)&lt;br /&gt;0.175000   0.000000   0.175000 (  0.175000)&lt;br /&gt;0.174000   0.000000   0.174000 (  0.174000)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;次に、Javaバックトレースに基づくRubyバックトレースと、若干インライン化し易くした、しかしまだインボーカ経由での動的呼び出しと、限定的なプリミティブ型呼び出し最適化によるものです。本質的には、完全な互換性を損なわずに（しかし実際には多少損ないつつ）我々が得られるJRuby 1.5としては最速です。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;0.383000   0.000000   0.383000 (  0.330000)&lt;br /&gt;0.109000   0.000000   0.109000 (  0.108000)&lt;br /&gt;0.111000   0.000000   0.111000 (  0.112000)&lt;br /&gt;0.101000   0.000000   0.101000 (  0.101000)&lt;br /&gt;0.101000   0.000000   0.101000 (  0.101000)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;次に、ここまで述べたすべての実行時最適化を行ったものです。これらの数値は、適切なガードにより低下するだろうことを覚えておいてください（それでもまだ非常に素晴らしいですが）:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;0.443000   0.000000   0.443000 (  0.376000)&lt;br /&gt;0.035000   0.000000   0.035000 (  0.035000)&lt;br /&gt;0.036000   0.000000   0.036000 (  0.036000)&lt;br /&gt;0.036000   0.000000   0.036000 (  0.036000)&lt;br /&gt;0.036000   0.000000   0.036000 (  0.036000)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;そして、主に再帰を用いた、非常に乱用されているもう一つのベンチマーク: tak関数の比較です。&lt;/p&gt;&lt;p&gt;静的な最適化のみで、可能な限りの高速化:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;1.750000   0.000000   1.750000 (  1.695000)&lt;br /&gt;0.779000   0.000000   0.779000 (  0.779000)&lt;br /&gt;0.764000   0.000000   0.764000 (  0.764000)&lt;br /&gt;0.775000   0.000000   0.775000 (  0.775000)&lt;br /&gt;0.763000   0.000000   0.763000 (  0.763000)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;そして実行時最適化:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;0.899000   0.000000   0.899000 (  0.832000)&lt;br /&gt;0.331000   0.000000   0.331000 (  0.331000)&lt;br /&gt;0.332000   0.000000   0.332000 (  0.332000)&lt;br /&gt;0.329000   0.000000   0.329000 (  0.329000)&lt;br /&gt;0.331000   0.000000   0.331000 (  0.332000)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以上のように、これらの小さなベンチマークでは、JRubyコンパイラの2～3時間のハックにより、これまでに達成した最も速いJRuby性能値よりも2～3倍速い数値を達成しました。&lt;/p&gt;&lt;h1&gt;頑張れJVM&lt;/h1&gt;&lt;p&gt;まだ説明していないトリックがあります。JVMは今も、大部分の仕事をこなしています。&lt;/p&gt;&lt;p&gt;古き良き動的呼出しの事例と、静的に最適化された事例では、JVMは従順に、与えられたすべてのものを最適化します。それはRubyのメソッド呼び出しを受け取り、インボーカとその最終的なメソッド呼び出し群をインライン化し、コアクラスメソッドをインライン化し（そうです。これは、JRubyがいつでも、RubyからRuby、JavaからRuby、またはRubyからJavaへ、適切な調整を加えてインライン展開できることを表しています）、これらを非常によく最適化します。しかしここに問題があります。JVMのデフォルトの設定は、Rubyではなく「Java」を最適化するのに調整されています。Javaでは、あるメソッドから他のメソッドへの呼び出しは確実に1ホップです。JRubyの動的呼び出しでは、最終的に目標に到達するまでにCallSiteとDynamicMethodをあちこち移動するため、3、4ホップかかるかもしれません。Hotspot（訳注: SunのJVM）はデフォルトでは高々9レベルまでの呼び出ししかインライン展開しないので、JRubyはその割当量をあっという間に消費してしまうことがわかるでしょう。それに加え、JavaからJavaへのメソッド呼び出しは中間コードを持たないため、バイトコードサイズのしきい値（訳注: HotSpotがメソッドのインライン化を始めるバイトコードサイズ）を消費しません。我々は本質的に、Javaのような&lt;em&gt;よりシンプルな&lt;/em&gt;言語に比べて、Hotspotの最適化能力のほんの一部しか利用していないのです。&lt;/p&gt;&lt;p&gt;次に、動的に最適化される事例を考えてください。今後多少のガードコードを追加しなければならないとしても、既に多くのメソッド呼び出しからCallSiteとDynamicMethodの両者を取り除きました。それは、9レベルのRubyメソッド呼び出し、またはRubyからコアメソッドまたはJavaを利用する9レベルのロジックがインライン展開できることを意味します。Hotspotに対して、最適化のための遙かによい全体像を与え、また滅多に利用されないデータ構造の更新のような、Rubyメソッド呼び出しを行う際の背景雑音を取り除きました。今後バックトレースを有効な形で取り出せるようにする必要がありますが、少なくとも二重のトラッキングはしていません。&lt;/p&gt;&lt;p&gt;つまり、我々がしなければならない事といえば、インライン化のためのすべての困難な作業をJRubyのコンパイラにさせるのではなく、JVMにそれをさせ、現在のJVMの最適化コンパイラに蓄積された何年分もの仕事から利益を得ることだけです。難問を解決するための一番良い方法は、誰かにそれを解かせることであり、JVMはここに示した難問を解くために素晴らしい仕事をしてくれます。我々は、JVMに対して魚を与えたり魚釣りを教えるのではなく、湖の地図を与えています。JVMは既に一流の漁師だからです。&lt;/p&gt;&lt;p&gt;これらの最適化には別の側面があります。我々の継続的なインタプリタ整備が、上手く行き始めているということです。インタプリタモードを持たない他のJVM言語は、いかなる動的最適化をも行おうとすると遙かに苦労します。端的に言えば、そのバイトコードが最初にどのように生成されたかを明示的に取り出しておかない限り、既に読み込んでしまったバイトコードを置き換えるのは大変困難です。JRubyではメソッドは実行時にいつでもインタプリタモードとJITモードを切り替わらなければならないため、最適化の過程ではるかに自由に行ったり来たりできます。&lt;/p&gt;&lt;p&gt;今はここまでです。数カ月のうちにJRuby 1.6をダウンロードしたらすべてが3倍（もしくは10倍！さらに100倍）高速化されている、ということは期待しないでください。いつこれらの最適化が安全に行われ得るか、必要であればユーザがどのように&lt;code&gt;すべての&lt;/code&gt;最適化を選択できるか、またコアコード（訳注: JRubyにおいてJavaで実装されたRubyのコード）をRubyに置き換え始めるのに十分な高速化ができるかどうかについて、まだまだやらなければいけないことの細かい部分が沢山あります。しかし、初期の結果は非常に有望であり、一部をすぐにリリースするだろうことは確実です。&lt;/p&gt;&lt;h2&gt;謝辞&lt;/h2&gt;&lt;p&gt;今回の記事ではnahiさんにご協力を頂きました。文責は訳者にあります。&lt;/p&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/618041604486425070/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/06/jruby.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/618041604486425070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/618041604486425070'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/06/jruby.html' title='JRubyのパフォーマンスの更なる向上を目指して'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-2096129432602835091</id><published>2010-05-12T16:36:00.001-05:00</published><updated>2010-05-12T16:36:15.405-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="1.5"/><category scheme="http://www.blogger.com/atom/ns#" term="1.5.0"/><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="release"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRuby 1.5.0 リリースのお知らせ</title><content type='html'>&lt;a href=&quot;http://jruby.org/2010/05/12/jruby-1-5-0.html&quot;&gt;原文&lt;/a&gt;：トム＝エネボ&lt;br /&gt;&lt;h2&gt;JRuby バージョン1.5.0&lt;/h2&gt;&lt;br /&gt;JRubyのバージョン1.5.0 のリリースを発表いたします。&lt;br /&gt;&lt;br /&gt;ホームページ: http://www.jruby.org/&lt;br /&gt;ダウンロード: http://www.jruby.org/download&lt;br /&gt;&lt;br /&gt;今まで最長のリリース期間（凡そ五ヶ月）を経た今回のリリースは不具合の修正の数も最多になりました。加えて、以下に示す通り、多くの新しい機能も含んでいます。不具合の内訳としてはRubyのメソッドの細かい仕様の修正が殆どです。その点から申しますと、JRuby 1.4.0から1.5.0へのアップグレードは容易でしょう。また、「JRubyから暫く遠ざかっていた」と仰るあなたも、この機会に是非JRubyを今一度試してみて下さい。&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;主な特長&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;高パフォーマンスなネイティブアクセスフレームワークと、FFIライブラリのサポート&lt;/li&gt;&lt;br /&gt;&lt;li&gt;*NIX用ネイティブ起動コマンド&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JavaのビルドツールであるAntのサポート、及びAntとRakeの統合の実現&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Windowsサポートの強化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;RubyからJavaの呼び出しの性能向上（バグ修正、メモリ消費の低下、スピードの向上）&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JSR-223,BSF,RedBridge等による組み込みAPIの強化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ruby標準ライブラリ　1.8.7p249、RubyGems 1.3.6、RSpec 1.3.0&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ruby-debugを標準で装備&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rails 3向けの修正&lt;/li&gt;&lt;br /&gt;&lt;li&gt;起動時間の短縮&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Object#object_id、Object#__id__の強化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Javaクラスのメモリ消費量の削減とJavaクラスのロードの高速化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;クラスローダが、jarを内包するjarに対応&lt;/li&gt;&lt;br /&gt;&lt;li&gt;open4ライブラリのバグを修正&lt;/li&gt;&lt;br /&gt;&lt;li&gt;jruby.jit.codeCache=dirオプションによりjitコンパイルされたスクリプト、メソッドなどをディスクに書き込み可能&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Javaクラスを生成するインターフェイスの新実装&lt;/li&gt;&lt;br /&gt;&lt;li&gt;jruby.ji.objectProxyCacheオプションによりOPCの無効化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JRuby::Synchronizedモジュールにより、クラスに属するオブジェクトのメソッド呼び出しを同期化可能&lt;/li&gt;&lt;br /&gt;&lt;li&gt;コアクラスの性能向上とJITコンパイラの向上&lt;/li&gt;&lt;br /&gt;&lt;li&gt;IRBでObjectSpaceの無効化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;mavenアーティファクトの修正&lt;/li&gt;&lt;br /&gt;&lt;li&gt;64ビットWindows、及びWindows 7用インストーラーのバグ修正&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JRuby 1.4から数えて1250を上回るコミット&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;謝辞&lt;/h2&gt;&lt;br /&gt;コミュニティーからの貢献には常に感謝しています。今回のリリースでは特に以下の人々からの貢献がありました。（順不同）&lt;br /&gt;&lt;br /&gt;David Calavera, Stephen Bannasch, Daniel Luz, Ian Dees, 大場光一郎さん, Hongli Lai, Hiroshi Nakamura, Colin Jones, 佐々木竹充さん, Roger Pack, Matjaz Gregoric, Joseph LaFata, Frederic Jean, Alex Coles, Lars Westergren&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/2096129432602835091/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/05/jruby-150.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/2096129432602835091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/2096129432602835091'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/05/jruby-150.html' title='JRuby 1.5.0 リリースのお知らせ'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-5533939751789644655</id><published>2010-05-04T15:34:00.001-05:00</published><updated>2010-05-12T16:34:37.235-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="1.5"/><category scheme="http://www.blogger.com/atom/ns#" term="1.5.0"/><category scheme="http://www.blogger.com/atom/ns#" term="1.5.0.RC3"/><category scheme="http://www.blogger.com/atom/ns#" term="release"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRuby 1.5.0.RC3 がリリースされました。</title><content type='html'>&lt;a href=&quot;http://jruby.org/2010/05/04/jruby-1-5-0-RC3.html&quot;&gt;原文&lt;/a&gt;：トム＝エネボ&lt;br /&gt;JRuby 1.5.0.RC3 のリリースをお知らせします。&lt;br /&gt;&lt;br /&gt;ホームページ: http://www.jruby.org/&lt;br /&gt;&lt;br /&gt;ダウンロード: http://www.jruby.org/download&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;RC2以降に修正されたバグを以下に示します。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/3742&quot;&gt;JRUBY-3742&lt;/a&gt;: Java native threads are not added to ThreadService.rubyThreadMap after being adopted.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4264&quot;&gt;JRUBY-4264&lt;/a&gt;: threadContextMap leaks RubyThread on death of adopted thread&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/5533939751789644655/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/05/jruby-150rc3.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/5533939751789644655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/5533939751789644655'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/05/jruby-150rc3.html' title='JRuby 1.5.0.RC3 がリリースされました。'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-1549831570393733197</id><published>2010-04-28T23:15:00.001-05:00</published><updated>2010-04-28T23:15:23.927-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="1.5"/><category scheme="http://www.blogger.com/atom/ns#" term="1.5.0"/><category scheme="http://www.blogger.com/atom/ns#" term="1.5.0.RC2"/><category scheme="http://www.blogger.com/atom/ns#" term="release"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRuby 1.5.0.RC2 がリリースされました。</title><content type='html'>&lt;a href=&quot;http://jruby.org/2010/04/28/jruby-1-5-0-RC2.html&quot;&gt;原文&lt;/a&gt;：トム＝エネボ&lt;br /&gt;JRuby 1.5.0.RC2 のリリースをお知らせします。恐らくこれが最後のRCになると思われます。&lt;br /&gt;&lt;br /&gt;ホームページ: http://www.jruby.org/&lt;br /&gt;&lt;br /&gt;ダウンロード: http://www.jruby.org/download&lt;br /&gt;&lt;br /&gt;RC1のリリース以降に修正されたバグを以下に示します。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/3153&quot;&gt;JRUBY-3153&lt;/a&gt;: IO rubyspec failures under IBM JDK6 Linux&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/3208&quot;&gt;JRUBY-3208&lt;/a&gt;: ant task api-docs runs out of memory, patch included&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4677&quot;&gt;JRUBY-4677&lt;/a&gt;: Java exceptions can&#39;t be rescued with &quot;rescue Exception&quot;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4680&quot;&gt;JRUBY-4680&lt;/a&gt;: jirb_swing broken: JRuby picking wrong constructor, with no obvious work around&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4704&quot;&gt;JRUBY-4704&lt;/a&gt;: &quot;Java wrapper with no contents&quot; error when subclassing a Runnable class in JRuby&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4710&quot;&gt;JRUBY-4710&lt;/a&gt;: Problems importing classes in default package&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4715&quot;&gt;JRUBY-4715&lt;/a&gt;: FFI::StructByValue missing layout and struct_class methods.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4721&quot;&gt;JRUBY-4721&lt;/a&gt;: FFI::Platform::CONF_DIR looks in wrong location for PPC Macs.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4724&quot;&gt;JRUBY-4724&lt;/a&gt;: Java class equality operator is order dependent&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4725&quot;&gt;JRUBY-4725&lt;/a&gt;: to_java_object no longer exists&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4729&quot;&gt;JRUBY-4729&lt;/a&gt;: System properties to set bindir and default rubygems paths&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4730&quot;&gt;JRUBY-4730&lt;/a&gt;: Unix jruby-1.5.0.RC1 distro includes rubygems/default/jruby_native.rb without native launcher&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4731&quot;&gt;JRUBY-4731&lt;/a&gt;: Mismatched default compilation prefix&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4733&quot;&gt;JRUBY-4733&lt;/a&gt;: Allow compilation of Ruby files for a specificic JVM version&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4734&quot;&gt;JRUBY-4734&lt;/a&gt;: Reduce &quot;multiple Java method&quot; warnings in unambiguous cases&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4735&quot;&gt;JRUBY-4735&lt;/a&gt;: install-gems ant target should not count on successful installation of jruby-launcher&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4737&quot;&gt;JRUBY-4737&lt;/a&gt;: Compatibility issue with Spring property from 1.4.0 to 1.5.0.RC1&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4738&quot;&gt;JRUBY-4738&lt;/a&gt;: test/testapp/testapp.exe appears twice in jruby-src-1.5.0.RC1.tar.gz&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4742&quot;&gt;JRUBY-4742&lt;/a&gt;: File::Stat throws a NPE when it doesn&#39;t find a file into a jar&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4747&quot;&gt;JRUBY-4747&lt;/a&gt;: read_nonblock error with couchrest&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4749&quot;&gt;JRUBY-4749&lt;/a&gt;: require &#39;rbconfig&#39; fails on GAE because of NullPointerException&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4750&quot;&gt;JRUBY-4750&lt;/a&gt;: ant-to-rake: &lt;rake&gt; task does not work when classpath is defined via taskdef&#39;s attribute&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4751&quot;&gt;JRUBY-4751&lt;/a&gt;: Java call to RubyBignum.to_s() returns generic object representation&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4754&quot;&gt;JRUBY-4754&lt;/a&gt;: NotImplementedError: the MD5() function is unimplemented on this machine&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4757&quot;&gt;JRUBY-4757&lt;/a&gt;: addressable gem doesn&#39;t work with --fast&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4760&quot;&gt;JRUBY-4760&lt;/a&gt;: File.open throws Errno::ENOENT when file inside jar is accessed using &quot;..&quot; (doubledot) in the path&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://bugs.jruby.org/4761&quot;&gt;JRUBY-4761&lt;/a&gt;: 1.9.2: Thread#backtrace&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/1549831570393733197/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/04/jruby-150rc2.html#comment-form' title='4 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/1549831570393733197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/1549831570393733197'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/04/jruby-150rc2.html' title='JRuby 1.5.0.RC2 がリリースされました。'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-7419540353041327858</id><published>2010-04-15T17:23:00.001-05:00</published><updated>2010-04-15T18:57:50.504-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="1.5"/><category scheme="http://www.blogger.com/atom/ns#" term="1.5.0"/><category scheme="http://www.blogger.com/atom/ns#" term="1.5.0.RC1"/><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="release"/><title type='text'>JRubyのバージョン1.5.0.RC1がリリースされました</title><content type='html'>&lt;a href=&quot;http://jruby.org/2010/04/15/jruby-1-5-0-RC1.html&quot;&gt;原文&lt;/a&gt;：トム＝エネボ&lt;br /&gt;&lt;h2&gt;JRuby バージョン1.5.0.RC1&lt;/h2&gt;&lt;br /&gt;JRubyのバージョン1.5.0.RC1を発表いたします。&lt;br /&gt;&lt;br /&gt;ホームページ: http://www.jruby.org/&lt;br /&gt;ダウンロード: http://www.jruby.org/download&lt;br /&gt;&lt;br /&gt;今まで最長のリリース期間（凡そ五ヶ月）を経た今回のリリースは不具合の修正の数も最多になりました。加えて、以下に示す通り、多くの新しい機能も含んでいます。不具合の内訳としてはRubyのメソッドの細かい仕様の修正が殆どです。その点から申しますと、JRuby 1.4.0から1.5.0.RC1へのアップグレードは容易でしょう。また、「JRubyから暫く遠ざかっていた」と仰るあなたも、この機会に是非JRubyを今一度試してみて下さい。以前あった不具合が解消されている可能性大です。1.5.0の正規リリースをより良い物にする為にどうぞご協力下さい。&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;主な特長&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;高パフォーマンスなネイティブアクセスフレームワークと、FFIライブラリのサポート&lt;/li&gt;&lt;br /&gt;&lt;li&gt;*NIX用ネイティブ起動コマンド&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JavaのビルドツールであるAntのサポート、及びAntとRakeの統合の実現&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Windowsサポートの強化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;RubyからJavaの呼び出しの性能向上（バグ修正、メモリ消費の低下、スピードの向上）&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JSR-223,BSF,RedBridge等による組み込みAPIの強化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ruby標準ライブラリ　1.8.7p249、RubyGems 1.3.6、RSpec 1.3.0&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ruby-debugを標準で装備&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rails 3向けの修正&lt;/li&gt;&lt;br /&gt;&lt;li&gt;起動時間の短縮&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Object#object_id、Object#__id__の強化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Javaクラスのメモリ消費量の削減とJavaクラスのロードの高速化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;クラスローダが、jarを内包するjarに対応&lt;/li&gt;&lt;br /&gt;&lt;li&gt;open4ライブラリのバグを修正&lt;/li&gt;&lt;br /&gt;&lt;li&gt;jruby.jit.codeCache=dirオプションによりjitコンパイルされたスクリプト、メソッドなどをディスクに書き込み可能&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Javaクラスを生成するインターフェイスの新実装&lt;/li&gt;&lt;br /&gt;&lt;li&gt;jruby.ji.objectProxyCacheオプションによりOPCの無効化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JRuby::Synchronizedモジュールにより、クラスに属するオブジェクトのメソッド呼び出しを同期化可能&lt;/li&gt;&lt;br /&gt;&lt;li&gt;コアクラスの性能向上とJITコンパイラの向上&lt;/li&gt;&lt;br /&gt;&lt;li&gt;IRBでObjectSpaceの無効化&lt;/li&gt;&lt;br /&gt;&lt;li&gt;mavenアーティファクトの修正&lt;/li&gt;&lt;br /&gt;&lt;li&gt;64ビットWindows、及びWindows 7用インストーラーのバグ修正&lt;/li&gt;&lt;br /&gt;&lt;li&gt;JRuby 1.4から数えて1250を上回るコミット&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;謝辞&lt;/h2&gt;&lt;br /&gt;コミュニティーからの貢献には常に感謝しています。今回のリリースでは特に以下の人々からの貢献がありました。（順不同）&lt;br /&gt;&lt;br /&gt;David Calavera, Stephen Bannasch, Daniel Luz, Ian Dees, 大場光一郎さん, Hongli Lai, Hiroshi Nakamura, Colin Jones, 佐々木竹充さん, Roger Pack, Matjaz Gregoric, Joseph LaFata, Frederic Jean, Alex Coles, Lars Westergren&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/7419540353041327858/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/04/jruby150rc1.html#comment-form' title='1 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/7419540353041327858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/7419540353041327858'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/04/jruby150rc1.html' title='JRubyのバージョン1.5.0.RC1がリリースされました'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-3498247008960765201</id><published>2010-03-03T01:05:00.001-06:00</published><updated>2010-06-15T22:20:35.393-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="startup"/><category scheme="http://www.blogger.com/atom/ns#" term="tips"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRubyの起動時間についてのヒント</title><content type='html'>&lt;a href=&quot;http://blog.headius.com/2010/03/jruby-startup-time-tips.html&quot;&gt;原文&lt;/a&gt;: チャールズ＝オリバー＝ナター&lt;br /&gt;&lt;br /&gt;JRubyはRuby言語の実装の中では一際起動が遅い事で悪名高くなってしまいました。一部は、JITの生成品がなくてブートストラップして動き出すまでに時間がかかってしまうJVMを使っているせいです。起動の際のボトルネックが報告されて原因が解明されればそれを除く努力を我々はしていますが、JRuby自体にも問題があります。起動の問題は、実は簡単な設定問題である事もしばしばです。JRubyの起動を早くするコツを幾つか見ていきましょう。&lt;br /&gt;&lt;br /&gt;注意。JRuby自体の起動は、他のJVM言語に較べると結構いい線いっていますが、MatzのRuby（一般的には最も速い実装とは言えない）の起動は素晴らしく早いです。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;クライアント用のJVMを使う&lt;/h3&gt;&lt;br /&gt;これが何と言っても一番手っ取り早い方法です。OpenJDKとSunのJDKを動かしているJVMであるHotSpotには、「クライアント用」と「サーバ用」の二種類のバックエンドがあります。「クライアント用」はバイトコードをコンパイルする時、最適化は最小限に、始めのうちにササッとやってしまうだけです。一方、「サーバ用」は大規模にしかも全体的に最適化をする訳ですが、これが出来るようになる時点に到着するには長い時間が掛かりますし、最適化の為には多くのリソースが必要です。&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;ごく最近まではJVMのインストールの多くは、この「クライアント用」を好む傾向にありましたので、JVMの起動時間は早かったのです。しかしながら、多くのオペレーティングシステムに最近使われているJVMに於いてデフォルトで使われるのは「サーバ用」か、或いは（「サーバ用」しかない）64ビットのJVMです。これによって、あなたもJRubyも何もしなくても起動時間が悪くなってしまいました。&lt;br /&gt;&lt;br /&gt;以下に例を挙げます。jruby -vを「サーバ用」のJVMで起動させ、RubyGemsをrequire（RubyGemsを多く使うアプリケーションで一番長く掛かる部分です）してみます。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby &amp;#10132; jruby -v&lt;br /&gt;jruby 1.5.0.dev (ruby 1.8.7 patchlevel 174) (2010-03-01 6857a4e) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_17) [x86_64-java]&lt;br /&gt;&lt;br /&gt;~/projects/jruby &amp;#10132; time jruby -e &quot;require &#39;rubygems&#39;; require &#39;active_support&#39;&quot;&lt;br /&gt;&lt;br /&gt;real 0m5.174s&lt;br /&gt;user 0m7.643s&lt;br /&gt;sys 0m0.422s&lt;br /&gt;&lt;br /&gt;~/projects/jruby &amp;#10132; time jruby -e &quot;require &#39;rubygems&#39;; require &#39;active_support&#39;&quot;&lt;br /&gt;&lt;br /&gt;real 0m5.068s&lt;br /&gt;user 0m7.662s&lt;br /&gt;sys 0m0.449s&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;なんと、RubyGemsとActiveSupportをロードするのに5秒以上も掛かってしまいました。この場合にはJVMが「64ビット、サーバ用」のJVMが使われています。このバックエンドはランタイムの性能はいいのですが、起動は酷いものがあります。-vのフラグを出した時にこのような結果が出るのならば、普通32ビットの「クライアント用」のJVMを「-d32」と言うフラグを使って走らせる事が出来ます。このようにします。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;~/projects/jruby &amp;#10132; export JAVA_OPTS=&quot;-d32&quot;&lt;br /&gt;&lt;br /&gt;~/projects/jruby &amp;#10132; time jruby -e &quot;require &#39;rubygems&#39;; require &#39;active_support&#39;&quot;&lt;br /&gt;&lt;br /&gt;real 0m2.320s&lt;br /&gt;user 0m2.583s&lt;br /&gt;sys 0m0.207s&lt;br /&gt;&lt;br /&gt;~/projects/jruby &amp;#10132; time jruby -e &quot;require &#39;rubygems&#39;; require &#39;active_support&#39;&quot;&lt;br /&gt;&lt;br /&gt;real 0m2.275s&lt;br /&gt;user 0m2.580s&lt;br /&gt;sys 0m0.207s&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;私の手元の、OS X 10.6を載せたMacBook Proでは、「クライアント用」JVMに切り替える事で50%を優に超える向上が観測出来ました。「-client」も試してみて下さい。32ビットのコンピュータでは「サーバ用」を優先する場合も有り得ますので、これと「-d32」とを組み合わせる必要があるかも知れません。色々試してみて、あなたの環境にあったフラグ組み合わせを見つけたら、プラットフォーム、-vの出力結果、そしてどれ程の効果があったかを報せて下さい。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;JVMの共用アーカイブを再生成する&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Java 5以降のHotSpot JVMではクラスデータシェアリング（CDS）というフィーチャが使えます。元々アップル社によってMac OS X用に開発されたこのフィーチャにより、一般的試用されるJDKのクラスを一つのアーカイブに集め共用メモリの場所にロードします。一度これを使うと、後からJVMを使った場合には、同じデータをリロードせずに、この読み込み専用の共用メモリを使う訳です。これが、ウィンドウズやMac OS XでJVMの起動時間が近年大幅に改善された大きな理由の一つです。この二つのオペレーティングシステムを使っている人はこのヒントは無視してもいいでしょう。&lt;br /&gt;&lt;br /&gt;しかしながら、インストーラが、アーカイブを最終的に試用する場所に解凍するだけのLinuxでは共用アーカイブが生成される事はまず無いと考えていいと思います。システムに、この共用アーカイブを再生成させるには、以下のコマンドと同等のものを走らせて下さい。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;headius@headius-desktop:~/jruby$ sudo java -Xshare:dump&lt;br /&gt;Loading classes to share ... done.&lt;br /&gt;Rewriting and unlinking classes ... done.&lt;br /&gt;Calculating hash values for String objects .. done.&lt;br /&gt;Calculating fingerprints ... done.&lt;br /&gt;Removing unshareable information ... done.&lt;br /&gt;Moving pre-ordered read-only objects to shared space at 0x94030000 ... done.&lt;br /&gt;Moving read-only objects to shared space at 0x9444bef8 ... done.&lt;br /&gt;Moving common symbols to shared space at 0x9444d870 ... done.&lt;br /&gt;Moving remaining symbols to shared space at 0x945154e0 ... done.&lt;br /&gt;Moving string char arrays to shared space at 0x94516118 ... done.&lt;br /&gt;Moving additional symbols to shared space at 0x945ac5b0 ... done.&lt;br /&gt;Read-only space ends at 0x94612560, 6169952 bytes.&lt;br /&gt;Moving pre-ordered read-write objects to shared space at 0x94830000 ... done.&lt;br /&gt;Moving read-write objects to shared space at 0x94ea64a0 ... done.&lt;br /&gt;Moving String objects to shared space at 0x94ee3708 ... done.&lt;br /&gt;Read-write space ends at 0x94f27448, 7304264 bytes.&lt;br /&gt;Updating references to shared objects ... done.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;多くのユーザにとって、JVMのクラスの多くがメモリに残る為、これで起動時間に大きな差が出る事が有ります。「-Xshare」は「-d32」または「-client」と一緒に使ってみる必要が有るかも知れません。他の「-Xshare」オプションなども試してみて下さい。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;JRubyのJITのスタートを遅らせるか、無効にする&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;JRubyのJITコンパイラの興味深い副作用の一つは、動いている時間が短い時など、場合によっては、アプリケーションの実行を遅くさせてしまう事が有るという事です。コンパイラを使うのは勿論無料では有りませんし、コンパイルした結果として出来たバイトコードをロード、チェック、リンクするのにも何らかのコストが掛かります。多くのコードを使うにも関わらず短いコマンドの場合には、JITを無効にするか、そのスタートを遅らせるのを試してみて下さい。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;これで見込める効果には限りがありますが、気が狂いそうになった時はやってみて下さい。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;他のRubyプロセスの呼び出しを避ける&lt;/h3&gt;&lt;br /&gt;Kernel#system、Kernel#exec、及びバッククォートを用いて他のRubyプロセスを呼び出すのはRubyist一般によく見られるパターンです。例えば、テストを実行するのに綺麗な環境を用意する必要がある場合などは頷けるのですが、このようなプロセスの呼び出しはランタイム全体に大きな影響を及ぼします。&lt;br /&gt;&lt;br /&gt;JRubyが#system、#exec、或いはバッククォートに出くわすと、まず最初に今現在走っているJVMを使って処理を行おうとします。JRubyは昔から（複数のRuby環境が同じプロセスないで動くという）所謂「マルチVM」による実行をサポートしていましたので、こうする事でサブプロセスの呼び出しを素早く行う事が出来ます。実際、Nailgun（これについては後にもっと詳しく触れます）はこれの応用によって複数のJRubyのコマンド実行環境を隔離しているのです。これでパフォーマンスの向上は見込めますが、それでも尚そのようなJRubyプロセスは新規の綺麗なクラスとランタイムを必要としますので、起動には時間が掛かります。&lt;br /&gt;&lt;br /&gt;最悪の場合、（例えばsystem &#39;ruby -e blah &gt; /dev/null&#39;の様に）シェルのリダイレクトを含むなどするとJRubyを同じJVMで起動させる事が出来ません。この場合、JRubyは全く新しくJVMを起動せざるを得ず、JRubyの起動時間というコストを、もう一度全部払う羽目になってしまいます。&lt;br /&gt;&lt;br /&gt;出来る事ならば、このようにRubyを呼び出すのを避けるか、Nailgunの様なツールを使うか、specサーバ等を使って同じプロセスを何度も何度も再利用するのが良いでしょう。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;起動時の処理をなるべく少なくする&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;自分で書かなかったコードが起動時に色々とやってしまう場合が多い（凡その場合それはRubyGemsそのものです）でしょうから、このヒントはあまり参考にならないかも知れません。JRubyが直面する悲しい事実の一つはJVMの上での実装であるという事、そしてJVMのエンジンが温まるまでに時間が掛かり、開始当初のコードは後からのコードに較べて遅いという事です。加えて、JRubyが、RubyのコードをJITコンパイルしてバイトコードにするまでには件のコードを何度か実行するという事を考慮すると、JRubyは立ち上がりがあまり良くないという事が解るでしょう。&lt;br /&gt;&lt;br /&gt;不可避なものを後回しにしようとしているように見えるかも知れませんが、起動時にあまり何もしない事で思いがけず良い結果が得られる場合もあります。ウィンドウが表示されるまで、或いはサーバの準備が出来るまで、重い処理を無くす事が出来れば、立ち上がりには付き物のパフォーマンス低下から逃れる（またはその低下を分散させる）ことが出来るかも知れません。ディスクに置いたキャッシュを上手く使とか、殆ど読み込むだけのデータはキャッシュとしてセーブしておいて起動時にはこれをリロード、再処理する、といったように、立ち上がりのアルゴリズムの改良も効果的です。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Nailgunを試す&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;JRuby 1.3ではNailgunのサポートを実装しました。Nailgunは、一つのJVMを複数回に渡る呼び出しに再利用出来るようにする小さなライブラリとクライアント用ツールです。これを使うと、ちょっとしたJRubyのコマンドの起動は何十倍も早くなるかも知れません。詳細は&lt;a href=&quot;http://blog.headius.com/2009/05/jruby-nailgun-support-in-130.html&quot;&gt;この記事&lt;/a&gt;を読んで下さい。&lt;br /&gt;&lt;br /&gt;Nailgunは魔法の弾丸のように見えるかも知れませんが、残念な事に、RubyGemsの起動、或いはRailsアプリケーションの立ち上がり等、或る種のよく見受けられる使用例ではあまり効果がありません。Rubyプロセスを何度も呼び出しするような場合にも効果は期待出来ません。いずれにしても、試してみて、効果があったかどうか報せて下さい。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;JVMのフラグを色々試してみる&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;JVMには起動時間の短縮（或いは延長）に役立つフラグが数多くあります。試してみるべきフラグのリストは私の書いた&lt;a href=&quot;http://blog.headius.com/2009/01/my-favorite-hotspot-jvm-flags.html&quot;&gt;この記事&lt;/a&gt;を、ヒープのサイズとガーベージコレクターに影響を及ぼすフラグに特に注意して、読んで下さい。特別に効果のあった組み合わせが見つかったら、是非報告をお願いします。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;ボトルネックの発見に協力をお願いします&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;JRubyの起動時間の短縮には、あなたのようなユーザからの起動時間についての調査が大きく貢献しています。ちょっと弄くってみて、或るライブラリのロードに法外な時間が掛かる（又は起動時に膨大な処理をする）と判明した場合、（ハードディスクがスラッシングする、メモリバスが飽和する等）CPU以外の何かがネックになって起動が遅いのならば、JRubyや、ロードしようとしているライブラリのコードに何か改良の余地が有るのかも知れません。ちょっと掘り下げてみて下さい。思わぬ発見が有るかも知れません。&lt;br /&gt;&lt;br /&gt;調査の際に役立ちそうなフラグはこういったものが有ります。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;--sampleはJVMのサンプリングプロファイラーをオンにします。特に正確ではありませんが、桁外れのボトルネックとなるようなものはリストの上に出てくる筈です。&lt;/li&gt;&lt;li&gt;-J-Xrunhprorf:cpu=timesはJVMのhprofプロファイラーをオンにして、結果をjava.hprof.txtにセーブします。コードの実行は格段と遅くなりますが、JRubyやJDKのコードの低いレベルでのタイミングをより正確に知ることが出来ます。&lt;/li&gt;&lt;li&gt;-J-Djruby.debug.loadService.timing=trueは、起動時間の大部分を占める、requireに掛かった時間を、程々の精度で書き出してくれます。&lt;/li&gt;&lt;li&gt;ウィンドウズではtimeコマンドに当たるものがありませんが、-bをJRubyに渡す事で（&#39;jruby -b …&#39;といった具合です）これと同様の結果を（JVMの起動に掛かった時間を除いて）得る事が出来ます。&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;私たちがお手伝いいたします&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;時として、JRubyにある明らかな設定ミスやバグによってアプリケーションの起動が遅くなってしまう事があります。起動時間がここに挙げて或る例と余りに違いすぎるのは、あなたが使っている環境に問題が有る可能性が大です。そんな場合にはJRubyのメーリングリストに投稿するか、IRCに参加するかして下さい。私たちが、他のJRubyユーザと共に、お手伝いします。</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/3498247008960765201/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/03/jruby.html#comment-form' title='2 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/3498247008960765201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/3498247008960765201'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/03/jruby.html' title='JRubyの起動時間についてのヒント'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-8934810721402198488</id><published>2010-02-24T07:56:00.001-06:00</published><updated>2010-03-03T01:07:11.868-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ActiveRecord"/><category scheme="http://www.blogger.com/atom/ns#" term="ActiveRecord-JDBC-Adapter"/><category scheme="http://www.blogger.com/atom/ns#" term="JDBC"/><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="Rails3"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRubyとRails 3を仲良くさせる方法</title><content type='html'>&lt;a href=&quot;http://blog.nicksieger.com/articles/2010/02/24/jruby-and-rails-3-sitting-in-a-tree&quot;&gt;原文&lt;/a&gt; ニック＝シーガー&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;概要&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;jruby -S rails newapp -m http://jruby.org/rails3.rb&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Rails 3のアプリを生成する際にはJRuby専用のテンプレート(&lt;code&gt;-m http://jruby.org/rails3.rb&lt;/code&gt;)を使用して下さい。&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;詳細&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;rubygemsのバグの為、bundlerはバージョン0.9よりも古い物全てをアンインストールする必要があります。&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;$ jruby -S gem install rails --pre --no-rdoc --no-ri&lt;br /&gt;Successfully installed i18n-0.3.3&lt;br /&gt;Successfully installed tzinfo-0.3.16&lt;br /&gt;Successfully installed builder-2.1.2&lt;br /&gt;Successfully installed memcache-client-1.7.8&lt;br /&gt;Successfully installed activesupport-3.0.0.beta&lt;br /&gt;Successfully installed activemodel-3.0.0.beta&lt;br /&gt;Successfully installed rack-1.1.0&lt;br /&gt;Successfully installed rack-test-0.5.3&lt;br /&gt;Successfully installed rack-mount-0.4.7&lt;br /&gt;Successfully installed abstract-1.0.0&lt;br /&gt;Successfully installed erubis-2.6.5&lt;br /&gt;Successfully installed actionpack-3.0.0.beta&lt;br /&gt;Successfully installed arel-0.2.1&lt;br /&gt;Successfully installed activerecord-3.0.0.beta&lt;br /&gt;Successfully installed activeresource-3.0.0.beta&lt;br /&gt;Successfully installed mime-types-1.16&lt;br /&gt;Successfully installed mail-2.1.3&lt;br /&gt;Successfully installed text-hyphen-1.0.0&lt;br /&gt;Successfully installed text-format-1.0.0&lt;br /&gt;Successfully installed actionmailer-3.0.0.beta&lt;br /&gt;Successfully installed thor-0.13.3&lt;br /&gt;Successfully installed railties-3.0.0.beta&lt;br /&gt;Successfully installed bundler-0.9.7&lt;br /&gt;Successfully installed rails-3.0.0.beta&lt;br /&gt;24 gems installed&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;続けて&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;$ jruby -S gem install activerecord-jdbcsqlite3-adapter --no-rdoc --no-ri&lt;br /&gt;Successfully installed activerecord-jdbc-adapter-0.9.3-java&lt;br /&gt;Successfully installed jdbc-sqlite3-3.6.3.054&lt;br /&gt;Successfully installed activerecord-jdbcsqlite3-adapter-0.9.3-java&lt;br /&gt;3 gems installed&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;最後に&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;$ jruby -S rails newapp -m http://jruby.org/rails3.rb&lt;br /&gt;      create&lt;br /&gt;...(app creation)...&lt;br /&gt;       apply  http://jruby.org/rails3.rb&lt;br /&gt;       apply    http://jruby.org/templates/default.rb&lt;br /&gt;        gsub      Gemfile&lt;br /&gt;         run      jruby script/rails generate jdbc from &quot;.&quot;&lt;br /&gt;...(warnings omitted)...&lt;br /&gt;       exist  &lt;br /&gt;      create  config/initializers/jdbc.rb&lt;br /&gt;      create  lib/tasks/jdbc.rake&lt;br /&gt;$ cd newapp&lt;br /&gt;$ jruby script/rails server&lt;br /&gt;...(warnings omitted)...&lt;br /&gt;=&amp;gt; Booting WEBrick&lt;br /&gt;=&amp;gt; Rails 3.0.0.beta application starting in development on http://0.0.0.0:3000&lt;br /&gt;=&amp;gt; Call with -d to detach&lt;br /&gt;=&amp;gt; Ctrl-C to shutdown server&lt;br /&gt;[2010-02-23 19:44:26] INFO  WEBrick 1.3.1&lt;br /&gt;[2010-02-23 19:44:26] INFO  ruby 1.8.7 (2010-02-23) [java]&lt;br /&gt;[2010-02-23 19:44:26] INFO  WEBrick::HTTPServer#start: pid=16449 port=3000&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src=&quot;http://img.skitch.com/20100224-eik9e957x7uu8k5x8y4xgt9jes.jpg&quot; alt=&quot;rails-welcome&quot;/&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;おさらい&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;最善の結果の為、RubyGems 1.3.6を搭載している&lt;a href=&quot;http://ci.jruby.org/snapshots&quot;&gt;JRuby 1.5.0devのスナップショット&lt;/a&gt;を使用して下さい。JRuby　1.5ももう少しでリリースされます。加えて&lt;a href=&quot;http://rubyforge.org/forum/forum.php?forum_id=36489&quot;&gt;最新の&lt;code&gt;activerecord-jdbc-adapter&lt;/code&gt; 0.9.3&lt;/a&gt;がRails 3との互換性の為には必要です。&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;JRubyでのRailsの使用感はどんどん良くなって行きます。&lt;/p&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/8934810721402198488/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/02/jrubyrails-3.html#comment-form' title='2 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/8934810721402198488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/8934810721402198488'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/02/jrubyrails-3.html' title='JRubyとRails 3を仲良くさせる方法'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-8048183660056729908</id><published>2010-02-23T01:22:00.001-06:00</published><updated>2010-02-23T18:14:36.695-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ant"/><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="Rake"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>RakeとAntを一緒に</title><content type='html'>&lt;a href=&quot;http://www.engineyard.com/blog/2010/rake-and-ant-together-a-pick-it-n-stick-it-approach/&quot;&gt;原文&lt;/a&gt;: トム＝エネボ&lt;br /&gt;&lt;br /&gt;JRuby 1.5リリースに含まれる新しいライブラリをレポジトリーに先日コミットしました。これについて述べる前にこの下にでている写真を見て色々と思いを巡らして下さい。そう！私たち皆の模範となるミスター・ポテトヘッドです。ミスター・ポテトヘッドは私たちを数時間に渡って楽しませる（少なくともおそらく楽しませてくれていたであろう）、柔軟なただのオモチャではなくて、澱粉質を多く含む食べ物でもあるのです。&lt;br /&gt;&lt;div style=&quot;float: right; width: 400px; overflow: hidden; background: none repeat scroll 0% 0% #cccccc; text-align: center; clear: right; font-size: 75%; color: #666666; padding: 0pt 0pt 10px; margin: 10px 0pt 10px 10px;&quot;&gt;&lt;img style=&quot;margin: 0;padding: 10px&quot; src=&quot;http://farm4.static.flickr.com/3158/2997761212_177aaac05b.jpg&quot; alt=&quot;&quot; width=&quot;360&quot; height=&quot;239&quot; /&gt;&lt;p&gt;ミスター・ポテトヘッド&lt;br /&gt; &lt;br /&gt;(&lt;a href=&quot;hthttp://www.flickr.com/photos/mymollypop/&quot; &gt;MyMollyPop&lt;/a&gt;さんの写真)&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;ちょっとトンチンカンな事を言っているな、と思う前にちょっと考えてみて下さい。実際のところ、私たちがプログラマとして日常やっているのは、ミスター・ポテトヘッドを造り上げているようなものではないですか。ソフトウェアを造り上げるという問題に私たちが直面した時、求められているのは、さまざまな部品をくっつけるだけではなく、部品を最も綺麗に組み合わせる事です。ソフトウェアデザインとは正しくジャガイモを飾り付けるようなものです。この記事の「ジャガイモ」はソフトウェアです。&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;ビルドのためのツール&lt;/h2&gt;&lt;br /&gt;Javaにおいて、Antは800ポンド（360㌔強）のジャガイモと言える位のビルドのためのツールの「重鎮」です。AntはJavaをビルドする環境の殆ど全てにあると言っていいでしょう。私は、Antを「心の底から好きだ」と言ってのける人には今までにたった一人しか出会っていません。&lt;br /&gt;&lt;br /&gt;大抵は、Antは構文的には見苦しいが与えられた仕事をきちんと成し遂げてくれる信頼出来るツールとして一目置いてるというところでしょう。命令型プログラミングにあまり適さないのにも不平があると思いますが、これは元来の仕様としてそうであるように思われますが、これを歓迎するプログラマはそう多くはないでしょう。&lt;br /&gt;&lt;br /&gt;RubyではRakeを使います。Antとは対照的に、Rakeの構文は綺麗です。RubyでDSLのような物を書く為のAPIであるRakeにおいてはRubyで使える物ならば何でも使えます。その一方で、Javaの世界ではよくやるような作業をするのにはAntにあるようなプラットフォームに依存しないタスクを持ち合わせていません。その為、シェルを使ったりする羽目になってしまって、これもある程度は動くのですが、Windowsで動かそうとすると悲しい目に遭ってしまいます。&lt;br /&gt;&lt;br /&gt;現実的に言うと、Javaをよく使っている人たちは他のビルド法に関心を示しはするものの、挙って数多くのプロジェクトをAnt以外のツールに移行はしないでしょう。仮にRakeに心惹かれていても、Antで当然の事としてやっているような事をRakeで成す為に四苦八苦する事になるのです。…今までは。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ユースケース&lt;/h2&gt;&lt;br /&gt;JRubyにおけるRakeとAntの統合では以下のユースケースを扱います。&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;RakeでAntで定義されているタスクとタイプを呼ぶ。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;AntからRakeを呼べるようにする。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;RakeのタスクをAntのターゲットとしてインポート出来るようにする。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;RakeからAntを呼べるようにする。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;AntのターゲットをRakeのタスクとして呼べるようにする。&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;一つずつ見ていきましょう。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;RakeでAntで定義されているタスクとタイプを呼ぶ&lt;/h3&gt;&lt;br /&gt;実を言うと、AntはJRubyでは組み込みのライブラリに過ぎません。Rakeで使わないで、スクリプトを書いてしまう事も可能です。&lt;br /&gt;&lt;pre&gt;require &#39;ant&#39;&lt;br /&gt; &lt;br /&gt;ant do&lt;br /&gt;  build_dir = &quot;java_build&quot; # Regular Ruby variables interact fine&lt;br /&gt; &lt;br /&gt;  # But defining and consuming Ant properties is fine&lt;br /&gt;  property :name =&amp;gt; &quot;src.dir&quot;, :value =&amp;gt; &quot;java_src&quot;&lt;br /&gt; &lt;br /&gt;  path(:id =&amp;gt; &quot;project.class.path&quot;) do&lt;br /&gt;    pathelement :location =&amp;gt; &quot;classes&quot;&lt;br /&gt;  end&lt;br /&gt; &lt;br /&gt;  mkdir :dir =&amp;gt; build_dir&lt;br /&gt; &lt;br /&gt;  javac(:destdir =&amp;gt; build_dir) do&lt;br /&gt;    classpath :refid =&amp;gt; &quot;project.class.path&quot;&lt;br /&gt;    src { pathelement :location =&amp;gt; &quot;${src.dir}&quot; }&lt;br /&gt;  end&lt;br /&gt; &lt;br /&gt;  jar :destfile =&amp;gt; &quot;simple_compile.jar&quot;, :basedir =&amp;gt; build_dir&lt;br /&gt;end&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;この例では、Antクラスのオブジェクトを生成して、ディレクトリを作り、Javaのソースコードをコンパイルし、最後にその結果をjarに入れます。これは皆Antのタスクで、全てのプラットフォームで動きます。凄いでしょう。しかしまだ依存関係の管理が欠けています。これはRakeにやらせましょう。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;require &#39;ant&#39;&lt;br /&gt; &lt;br /&gt;build_dir = &quot;java_build&quot;&lt;br /&gt;file build_dir&lt;br /&gt; &lt;br /&gt;task :setup =&amp;gt; build_dir do&lt;br /&gt;  ant.property :name =&amp;gt; &quot;src.dir&quot;, :value =&amp;gt; &quot;java_src&quot;&lt;br /&gt;  ant.path(:id =&amp;gt; &quot;project.class.path&quot;) do&lt;br /&gt;    pathelement :location =&amp;gt; &quot;classes&quot;&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt; &lt;br /&gt;task :compile =&amp;gt; :setup do&lt;br /&gt;  ant.javac(:destdir =&amp;gt; build_dir) do&lt;br /&gt;    classpath :refid =&amp;gt; &quot;project.class.path&quot;&lt;br /&gt;    src { pathelement :location =&amp;gt; &quot;${src.dir}&quot; }&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt; &lt;br /&gt;task :jar =&amp;gt; :compile do&lt;br /&gt;  ant.jar :destfile =&amp;gt; &quot;simple_compile.jar&quot;, :basedir =&amp;gt; build_dir&lt;br /&gt;end&lt;br /&gt; &lt;br /&gt;task :default =&amp;gt; :jar&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;（ここで一つ注意。RakeとAntを両方使える訳ですからAntのプロパティを設定する必要はありません。Rubyの変数や定数を使えばいいんです。十人十色ですね。）&lt;br /&gt;&lt;br /&gt;Rakefileの中でAntのタスクを使用するのが如何に簡単かが判ると思います。JRubyのAntライブラリは、Antの元の構文に素直に対応するAPIの集合です。何をどうすればいいのかは直ぐに理解出来るでしょう。&lt;br /&gt;&lt;br /&gt;Rakeでは命令型プログラミングが出来るという長所があると既に述べました。このようなAntのコード片について考察してみましょう。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;      &amp;lt;java classname=&quot;${mainclass}&quot;&amp;gt;&lt;br /&gt;        &amp;lt;arg value=&quot;--command&quot;/&amp;gt;&lt;br /&gt;        &amp;lt;arg value=&quot;maybe_install_gems&quot;/&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;arg value=&quot;--no-ri&quot;/&amp;gt;&lt;br /&gt;        &amp;lt;arg value=&quot;--no-rdoc&quot;/&amp;gt;&lt;br /&gt;        %lt;arg value=&quot;--env-shebang&quot;/&amp;gt;&lt;br /&gt;      &amp;lt;/java&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;これを命令型に直すとこんな感じ&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;command = &quot;--command may_install_gems --no-ri --no-rdoc --env-shebang&quot;&lt;br /&gt;ant.java :classname =&amp;gt; &quot;${mainclass}&quot; do&lt;br /&gt;  command.split(/\s+/).each { |value| arg :value =&amp;gt; value }&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;もしもあなたがRakeのユーザであるならば、こちらの方を使おうと決断するのは用意でしょう。その他のAntのタスクの中にはJavaらしい事をするのでなくたって便利な物というのもあります。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;AntからRakeを呼べるようにする&lt;/h3&gt;&lt;br /&gt;或るAntプロジェクトと同等の物をRakeを使う事で書けるとしたら、そのプロジェクトをRake主導でやりたいと思うかもしれません。ところが、それでも尚AntからRakeを呼ぶ必要があるかも知れません。そういう時はこのRakeという名前のタスクで切り抜けましょう。&lt;br /&gt;&lt;br /&gt;上に挙げたRakefileとbuild.xmlとが共存するという事にすると、そのbuild.xmlの中ではこのようなコード片を使う事が出来ます。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br /&gt;&amp;lt;project name=&quot;foobar&quot; default=&quot;default&quot; basedir=&quot;.&quot;&amp;gt;&lt;br /&gt;  &amp;lt;description&amp;gt;Builds, tests, and runs the project foobar.&amp;lt;/description&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;target name=&quot;load-rake-task&quot;&amp;gt;&lt;br /&gt;    &amp;lt;taskdef name=&quot;rake&quot; classname=&quot;org.jruby.ant.Rake&quot;/&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;target name=&quot;default&quot; depends=&quot;load-rake-task&quot;&amp;gt;&lt;br /&gt;    &amp;lt;rake task=&quot;jar&quot;/&amp;gt;&lt;br /&gt;  &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;  ...&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;このAntスクリプトでdefaultターゲットを呼ぶと、まず始めにRakeのタスクが読み込まれ、それがRakeを呼び（ここではデフォルトであるRakefileをインプットとして使います）、それがRakeのデフォルトであるdefault、即ちjarタスクを呼ぶ訳です。これを元にしたシナリオは二つ考えられます。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1. Rakeを少しずつ試用する事が出来る&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;これは、あなたはRakeが好きだけれども、あなたの所属する開発チーム全体でRakeに移行するよう説得するのは難しいと思われる場合に有効です。何か新しい機能を入れる際にRakefileをプロジェクトの一部として忍ばせておいて、チームの他のメンバーに評価をしてもらうのです。もし気に入ってもらえれば残りを導入すればいいです…よね。Javaを主に使用している部署がビルドのシステムを一気に変えてしまうというのはとても考えられませんから、このように少しずつ導入していくのがよいでしょう。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. 他のJavaのツールとうまく統合する&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;もしもあなたがRakeに惚れ込んでいたとしても、NetBeans等のソフトウェアは、あなたのプロジェクトとうまくやって行くためにはbuild.xmlがある事を大前提としています。このような繋ぎがあれば、あなたのプロジェクトとAntを前提としているツールとの相性はばっちりです。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;RakeのタスクをAntのターゲットとしてインポート出来るようにする&lt;/h3&gt;&lt;br /&gt;上のRakeのタスクの大きな欠点は、それが一方通行であるという点です。Rakeを呼ぶ事は出来ますが、Rakeの側からはAntとは大した接触が有りません。Antのタスクを呼べはしますが、プロパティや他にどのようなAntのターゲットがbuild.xmlに定義されているのか等はさっぱり判りません。&lt;br /&gt;&lt;br /&gt;よりよい相互運用の為にはRakeImportというもう一つのAntタスクを使います。RakeImportを使うには、定められたRakefileと、それにより定められているタスクをAntの依存管理システムに登録する必要が有ります。例を見てみましょう。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;project name=&quot;foobar&quot; default=&quot;top-level&quot; basedir=&quot;.&quot;&amp;gt;&lt;br /&gt;    &amp;lt;description&amp;gt;Builds, tests, and runs the project foobar.&amp;lt;/description&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;taskdef name=&quot;rakeimport&quot; classname=&quot;org.jruby.ant.RakeImport&quot;/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;rakeimport/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;target name=&quot;top-level&quot; depends=&quot;its_in_rake&quot; /&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;target name=&quot;its_in_ant&quot;&amp;gt;&lt;br /&gt;      &amp;lt;echo message=&quot;ant: its_in_ant&quot;/&amp;gt;&lt;br /&gt;    &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/project&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;このファイルでRakeImportを用いる事を明示して、その後直ぐにこのタスクを呼びます。これにより以下に示すRakefileを読み込むと、そこに書かれているタスクの全てがAntに登録されます。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;task :its_in_rake =&amp;gt; [:setup, :its_in_ant]  do&lt;br /&gt;  puts &quot;it&#39;s in Rake&quot;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;task :setup do&lt;br /&gt;  puts &quot;setup in Rake&quot;&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ここでant top-levelを呼ぶと、以下のような結果が画面に出ます。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Buildfile: build.xml&lt;br /&gt;[rakeimport] (in /Users/enebo/work/akakamiari/samples/rake_import_example2)&lt;br /&gt;&lt;br /&gt;setup:&lt;br /&gt;setup in Rake&lt;br /&gt;&lt;br /&gt;its_in_ant:&lt;br /&gt;     [echo] ant: its_in_ant&lt;br /&gt;&lt;br /&gt;its_in_rake:&lt;br /&gt;it&#39;s in Rake&lt;br /&gt;&lt;br /&gt;top-level:&lt;br /&gt;&lt;br /&gt;BUILD SUCCESSFUL&lt;br /&gt;Total time: 7 seconds&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;これを見ると、AntのターゲットとRakeのタスクの両方が好ましい順序で実行されているのが解ります。its_in_antはits_in_rakeの従属性として実行され、そしてits_in_rakeはAntのターゲットであるtop-levelの従属性として実行されているという具合です。&lt;br /&gt;&lt;br /&gt;このレベルでの統合におけるシナリオは&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1. 最適のツールを選べる&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Rakeは命令型プログラミング環境を与えてくれますから、Antでは煩わしい（または自分でAntタスクをカスタマイズしなければ不可能な）事が非常に簡単に出来る事があります。そうしたものはRakeに移管しつつ、Antは残りの物に使う事が出来ます。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. Rakeに完全に移行する&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;前の節で、開発チームにRakeの有用性を示す為にRakeタスクを使いました。これにより、Antの依存グラフにRakeの機能を頼みとするタスクを滑り込ませていく事が出来ているでしょう。あなたのグループは主なビルドのツールとしてAntを使っているのでしょうが、Rakeに任せる部分が大きくなってきています。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;RakeからAntを呼べるようにする&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;ではここで反対側から見てみましょう。もしもあなたがすでにRakeのユーザであって、既存のAntファイルと拘わらなければならないならば、ここに良い解決策が有ります！先ず第一の方法ではAntをRakeから直接呼び出せます。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;task :call_ant do&lt;br /&gt;  ant &#39;-f my_build.xml my_target1&#39;&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;もう一つの方法では引数を渡す事も出来ます。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;args = [&#39;-f&#39;, &#39;my_build.xml&#39;, &#39;my_target1&#39;]&lt;br /&gt;task :call_ant do&lt;br /&gt;  ant args&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;信じられないかも知れませんが、ここでは`ant`を実行しているだけではありません。antは実際にJRubyの環境内部へと読み込まれているのです。JVMをもう一つ起動させる手間が要らないのが素晴らしいです。&lt;br /&gt;&lt;br /&gt;この節の始めに書いた通り、Antを呼び出すだけでいいとあなたが思うのならばそれでも構いません。でももっと深く拘わりたいのなら…&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;AntのターゲットをRakeのタスクとして呼べるようにする&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;ant_importは、Rankeの依存管理システムにAntの最上層のターゲットを登録するという点に於いて、antに優っています。一度AntのファイルをRakeにインポートしてしまえば、Antのタスクを単なるRakeのタスクであるかのように呼び出す事が出来ます。簡単な例を挙げます。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;task :ant_import do&lt;br /&gt;  ant_import&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;task :compile =&amp;gt; [:ant_import, :its_in_ant_setup] do&lt;br /&gt;  # Do some compilation&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;この例ではcompileというRakeのタスクが実行されるとant_importというタスクを読み込み、それが今度はディレクトリにあるbuild.xmlを読み込み、そしてAntのターゲット全てを読み込んでいます。ant_importを最上部で使わないのは、Antを使う必要がない時にはAntのターゲットを読み込むような無駄を避ける為です。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;細かい所を…&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;このコードはJRubyのトランクにコミットされたばかりです。この記事に書いてある例は全て動く筈ですが、何しろ新しいのでJRuby 1.5がリリースされるまでは多少の仕様変更があるかも知れません。ですから以下の二点を心に留めておいて下さい。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1. バグを発見して、このライブラリを改善する手助けをして下さい&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;もしこのライブラリに興味があるのなら、早いうちからプロジェクトに関わって、問題点を正したりライブラリを向上させる事が出来ます。この統合が&lt;em&gt;凄い&lt;/em&gt;ものになるか、ただ「良い」ものになるかはあなたの参加に掛かっているのかも知れません。&lt;br /&gt;&lt;br /&gt;始める際の注意点を挙げます。現在の仕様ではjruby-complete.jarを$ANT_HOME/libにコピーするのが最善だと思います。jruby-complete.jarを含むようにクラスパスを設定する事でも可能ですが、コピーした方が手っ取り早く、間違える危険を低く抑える事が出来るでしょう。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. 作りかけのソフトウェアを好まないのならJRuby 1.5をリリースを待って下さい&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;作りかけのソフトウェアを煩わしく思ったり、いじくったりする時間のない人たちも少なくありません。そうだとしても、ご心配は無用。1.5リリースまでには上手く動くようにします。中途半端な物をリリースして後味が悪くなったりしないように努力します。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;最後に&lt;/h2&gt;&lt;br /&gt;始めにミスターポテトヘッドの話をしたのは、色々な部品を組み合わせるのが時として最善の策だという事を示す為でした。理論的には、一からやり直して一貫性のある純粋な物を造り上げる事が出来れば良いのでしょう。でも実際的には、実生活での細かい事が常に邪魔をするもの。そんな時、全部書き直してしまうよりは、新しい技術を噛み合わせるという手があります。古い物を長期的な視野で置換するのなら、少しずつ変えていくのも良いでしょう。私が過去に携わった大規模な書換えプロジェクトは悉く失敗しました。部品を一つ一つ変えていくほうが成功の確率は高いのです。&lt;br /&gt;&lt;br /&gt;このRakeとAntとを統合するプロジェクトは、こうした小規模な変更を（或いは、二つのツールのそれぞれの良い部分を掻い摘んで使う事を）可能にします。また、この二つのツールはどちらも欠く事が出来ないのかも知れない、或いは、二つのツールのうちの一つをもう一つで完全に置き換えてしまうのは100%良い解決策ではないのかも知れない、という現実を具現化しています。&lt;br /&gt;&lt;br /&gt;質問、コメントはいつも通り大歓迎します。</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/8048183660056729908/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/02/rakeant.html#comment-form' title='3 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/8048183660056729908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/8048183660056729908'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/02/rakeant.html' title='RakeとAntを一緒に'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://farm4.static.flickr.com/3158/2997761212_177aaac05b_t.jpg" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-3843383305121634010</id><published>2010-01-10T00:41:00.001-06:00</published><updated>2010-01-11T09:32:42.547-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="Ant"/><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="Maven"/><category scheme="http://www.blogger.com/atom/ns#" term="Rake"/><category scheme="http://www.blogger.com/atom/ns#" term="Ruboto"/><category scheme="http://www.blogger.com/atom/ns#" term="RubyGems"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>大忙しの一週間。アンドロイド、Maven、Rake、C拡張、そして…</title><content type='html'>&lt;a href=&quot;http://blog.headius.com/2010/01/busy-week-jruby-with-android-maven-rake.html&quot;&gt;原文&lt;/a&gt;：　チャールズ＝オリバー＝ナター&lt;br /&gt;&lt;br /&gt;（最後のブログ記事からどれ位経ったでしょうか?正解は「長い間」。カンファレンス続きで大忙しだった秋が終ったので、もっとブログを書くつもりです。これからは、一月に三つも会議に出かけないように忠告して下さい。）&lt;br /&gt;&lt;br /&gt;やあ！この一週間はとても忙しかったです。でも、僕らは元気でせっせとコード書いてるって解るように、JRubyで何が起こってるかを見ていきましょう。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;アンドロイド&lt;/h2&gt;&lt;br /&gt;今週の頭にJan Berkelの手伝いをやってRuboto IRBを最新のアンドロイド携帯環境で走らせる事に成功しました。細かい手直しが二つ三つ必要だったのと、Janが手伝うのに興味があるというので、この変更を追加して彼をRubotoのコミッタに追加しました。&lt;br /&gt;&lt;br /&gt;Ruboto IRBのレポジトリはこちら→&lt;a href=&quot;http://github.com/headius/ruboto-irb&quot;&gt;http://github.com/headius/ruboto-irb&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;最近、アンドロイド上で動くJRubyに対する私の興味が増してきました。極最近の事ですが、JRubyはJVMで動くメジャーな言語の内ではアンドロイド携帯で動いている間に&lt;strong&gt;新規の&lt;/strong&gt;コードを作って動かす事が出来る凡そ唯一の言語なのだと思い至ったんです。GroovyやScalaやClojureでは双方向型のシェルを造るのは不可能。というのも、これらの言語はソースコードを一旦JVMのバイトコードにコンパイルする必要があって、JVMのバイトコードはDalvikのVMでは直接には動かないからです。&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;今週Ruboto IRBをいじくってて、もっと面白い事に気がつきました。以前にJRubyがアンドロイドで上手くいかなかった原因となっていたバグのほとんど全てが解消されていたのです!特筆すべきはandroid.*で現されるクラスにリフレクションが、アンドロイド1.6とアンドロイド2.0両方に備わった点が挙げられます。これがどうして凄いか、っていうと、Ruboto IRBを使うことでアンドロイドAPIの何でも弄くる事が出来るからです。&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://img.skitch.com/20100108-1nr5rj4y7dpw4spfr9sf5w3ui3.jpg&quot;/&gt;&lt;br /&gt;&lt;br /&gt;この例はアンドロイドActivity（Ruboto IRBの中のIRBクラス）にアクセスして、新しいWebViewインスタンスを造り、ちょっとしたHTMLをロードしてWebViewの中身を入れ替えています。それもユーザからのインプットを使って。携帯の上で。凄いです。&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://img.skitch.com/20100108-dagfkf1thqktftghpnaigxhus5.jpg&quot;/&gt;&lt;br /&gt;&lt;br /&gt;皆さんが、このRubotoの凄い力を悪用することなく、善の為だけに使ってくれると信じています。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;RubyGemsとMavenの連携&lt;/h2&gt;&lt;br /&gt;JRubyの第一の使命はRubyの実装です。その結果、Javaプラットフォームとの統合を蔑（ないがし）ろにすることが時としてありました。でも、Ruby 1.8.7との互換性がガッチリとしてきて、1.9への取り組みが本格的になってきた今、Javaに再び目を向ける時がやって来ました。&lt;br /&gt;&lt;br /&gt;プログラミング言語との統合を図る上で欠かせないのが、その言語を取り巻くツールをどうサポートするかです。そして、Javaでツールと言えば、必ずMavenが絡んできます。&lt;br /&gt;&lt;br /&gt;一年ほど前、MavenのアーティファクトをRubyGemsに取り入れるプロジェクトを始めました。MavenのアーティファクトとRubyGemsの対応は簡単に解ると思います。どちらにも依存性、名前、叙述、個別ID、バージョン、そして各々のパッケージを記述する決まったフォーマットが有ります。maven_gemプロジェクトは、この二つの世界の融合が可能であることを証明するものです。&lt;br /&gt;&lt;br /&gt;maven_gemのレポジトリはここ→&lt;a href=&quot;http://github.com/jruby/maven_gem&quot;&gt;http://github.com/jruby/maven_gem&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;このプロジェクトはこの秋に私が再び触れるまで埃を被ったままでしたが、Sonatypeの人たちに興味を持ってもらえたのをきっかけに、急速な進歩を遂げています。&lt;br /&gt;&lt;br /&gt;SonatypeのTamas Cservenak氏の御陰で、不可能だと一度は諦めていた事も可能になりました。それは、RubyGemsと全てのMavenアーティファクトとの完全な融合です。&lt;br /&gt;&lt;br /&gt;Nexus RubyGemsのレポジトリはここ→&lt;a href=&quot;http://github.com/cstamas/nexus-ruby-support&quot;&gt;http://github.com/cstamas/nexus-ruby-support&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;~/projects/jruby ➔ gem install com.lowagie.itext-rtf&lt;br /&gt;Successfully installed bouncycastle.bcmail-jdk14-138-java&lt;br /&gt;Successfully installed bouncycastle.bcprov-jdk14-138-java&lt;br /&gt;Successfully installed bouncycastle.bctsp-jdk14-138-java&lt;br /&gt;Successfully installed com.lowagie.itext-rtf-2.1.7-java&lt;br /&gt;4 gems installed&lt;br /&gt;Installing ri documentation for bouncycastle.bcmail-jdk14-138-java...&lt;br /&gt;Installing ri documentation for bouncycastle.bcprov-jdk14-138-java...&lt;br /&gt;Installing ri documentation for bouncycastle.bctsp-jdk14-138-java...&lt;br /&gt;Installing ri documentation for com.lowagie.itext-rtf-2.1.7-java...&lt;br /&gt;Installing RDoc documentation for bouncycastle.bcmail-jdk14-138-java...&lt;br /&gt;Installing RDoc documentation for bouncycastle.bcprov-jdk14-138-java...&lt;br /&gt;Installing RDoc documentation for bouncycastle.bctsp-jdk14-138-java...&lt;br /&gt;Installing RDoc documentation for com.lowagie.itext-rtf-2.1.7-java...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;これを使ってRhinoをインストールし、それをirbで使うとこんな感じです。&lt;br /&gt;&lt;a href=&quot;http://gist.github.com/271764&quot;&gt;http://gist.github.com/271764&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;この事がJRubyユーザにとって意味する事は重大です。JRuby 1.5以降では、公にアクセス出来るMavenレポジトリから、Javaのライブラリを、インストールまたは依存するライブラリの一つとして利用する事が出来るようになるのです。端的に言うと、6000を超える数の新しいライブラリをすぐに使えるということです。凄いでしょう?&lt;br /&gt;&lt;br /&gt;このプロジェクトはもう幾つか不具合（例えば、RubyGems自体が6000ものgemを含む索引を生成するのに苦労する点）がありますが、テスト用のサーバは既に動いています。JRuby 1.5RC1がリリースされるまでにはこのような点は解消するつもりです。興味のある人はJRubyメーリングリストへ是非参加して下さい。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Rake?Ant?両方やろう！&lt;/h2&gt;&lt;br /&gt;Javaとの統合についてのもう一つ触れておきたいのがトム＝エネボ氏がやっている、Rake（Rubyにおけるビルドのツール）とAntをシームレスに、相互に統合するプロジェクトです。これには以下の三つの側面が有ります。&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;	&lt;li&gt;RakeのタスクをAntで、逆にAntのタスクをRakeで使う。&lt;/li&gt;&lt;br /&gt;	&lt;li&gt;RakeのターゲットをAntから、逆にAntのターゲットをRakeから呼び出す。&lt;/li&gt;&lt;br /&gt;	&lt;li&gt;RakeとAntの両方を混ぜ合わせたビルド方式の構築&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;トムの作業はこれまでの所、第一点に焦点を合わせていましたが、他の二点についても作業が進んでいます。近いうちに、AntのスクリプトをRake用に書き換えて何の修正も加える事なく使えるようになったり、AntからRakeを呼び出したり、RakefileをAntターゲットの一つとして使用したり、といった事が可能になります。&lt;br /&gt;&lt;br /&gt;Rakeからbuild.xmlの内容を導いて、ターゲットに拠ってはAntのタスクを呼び出すような例がこれです。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;require &#39;ant&#39;&lt;br /&gt;&lt;br /&gt;ant.load &#39;build.xml&#39; # defines tasks :mkdir + :setup in ant!&lt;br /&gt;&lt;br /&gt;task :compile =&gt; [:mkdir, :setup] do&lt;br /&gt;  ant.javac(:srcdir =&gt; src_dir, :destdir =&gt; &quot;./build/classes&quot;) do&lt;br /&gt;    classpath :refid =&gt; &quot;project.class.path&quot; &lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;理想的には、統合する上で考えられるあらゆる場合にも対応して、RakeとAntの境界線をあやふやな物にしたいと考えています。ゆくゆくはJRubyのビルドをRakeに移す事が出来れば、皆が喜ぶでしょう。これもJRuby 1.5でリリースする予定です。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;C拡張の問題&lt;/h2&gt;&lt;br /&gt;後回し後回しにしてきたRubyの側面の一つが、C拡張です。C拡張のユーザやデベロッパへの悪意からそうしていたのでは決して有りません。何かのスイッチ一つでC拡張が魔法のように使えるようになったらどんなにか素晴らしいでしょう。問題なのは、RubyのC拡張のAPIがオブジェクトの内側を露呈し過ぎてしまって、そのようなAPIを小さいコストで提供するのが不可能であるという事。（なぜかというと、一つ一つの操作にメモリをコピーする必要が生じてしまうから。）&lt;br /&gt;&lt;br /&gt;代替案として模索しているのは、「C拡張APIのうち、『安全』な物をサポートし、『危険』な物については、それに取って代わる物を提供しよう」というもの。これを実現する為、ウェイン＝マイスナー氏によりC拡張APIとの繋ぎとなるライブラリがgithubに発表されました。&lt;br /&gt;&lt;br /&gt;レポジトリはここ→&lt;a href=&quot;http://github.com/wmeissner/jruby-cext&quot;&gt;http://github.com/wmeissner/jruby-cext&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;昨晩ちょっとこれに時間を割いてMac OS Xで動かしてみました。自分でやって驚いたんですが、（非常に）些細な物を動かす事が出来ました!&lt;br /&gt;&lt;br /&gt;Cで書かれている部分がこれ。MRI用に書くのとちっとも変わりません。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;ruby.h&amp;gt;&lt;br /&gt; &lt;br /&gt;VALUE HelloModule = Qnil;&lt;br /&gt;VALUE HelloClass = Qnil;&lt;br /&gt; &lt;br /&gt;VALUE say_hello(VALUE self, VALUE hello);&lt;br /&gt;VALUE get_hello(VALUE self);&lt;br /&gt; &lt;br /&gt;void&lt;br /&gt;Init_defineclass()&lt;br /&gt;{&lt;br /&gt;    HelloClass = rb_define_class(&quot;Hello&quot;, rb_cObject);&lt;br /&gt;    rb_define_method(HelloClass, &quot;get_hello&quot;, get_hello, 0);&lt;br /&gt;    rb_define_method(HelloClass, &quot;say_hello&quot;, say_hello, 1);&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;VALUE&lt;br /&gt;say_hello(VALUE self, VALUE hello)&lt;br /&gt;{&lt;br /&gt;    return Qnil;&lt;br /&gt;}&lt;br /&gt;VALUE&lt;br /&gt;get_hello(VALUE self)&lt;br /&gt;{&lt;br /&gt;    return rb_str_new2(&quot;Hello, World&quot;);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;これを読み込んで実行するRubyのコードがこれ。ModuleLoaderについての部分は最終のリリースバージョンではrequire/loadとして隠してしまう予定である事に注意して下さい。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;require &#39;java&#39;&lt;br /&gt; &lt;br /&gt;m = org.jruby.cext.ModuleLoader.new&lt;br /&gt;m.load(self, &quot;defineclass&quot;)&lt;br /&gt; &lt;br /&gt;h = Hello.new&lt;br /&gt;puts &quot;Hello.new returned #{h.inspect}&quot;&lt;br /&gt;puts &quot;h.get_hello returns #{h.get_hello}&quot;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;C拡張APIのうち、JRubyではサポートする予定のないのは、RSTRING、RARRAY、RHASH等の文字配列、配列、ハッシュの内側へのアクセスを可能にする物や、Rubyのスレッドやランタイムに関する物などです。つまり、JNI（JVMのC拡張API）にそぐわない物はサポートする予定はありません。&lt;br /&gt;&lt;br /&gt;これはC拡張を使用するユーザが主導のプロジェクトです。JRubyにおけるC拡張APIの実現に興味があるのなら、是非僕らに協力して下さい。僕らはJavaとRubyのサポートに忙しいばかりでなく、C拡張を書く事自体にはあまり慣れていません。上に挙げたレポジトリを覗いてみて、JRubyのメーリングリストに参加してください。力を合わせてやっていきましょう。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2010年のJRuby&lt;/h2&gt;&lt;br /&gt;この他にも2010年のJRubyには目玉が一杯です。コンパイルしたり、シリアル化したり、注釈を付けたり、設定ファイルで指し示す事が出来る、「本物」のJavaクラスをRubyのコードで作り出す事が可能になるでしょう。JRubyを商用している人達向けに、サポートの提供（バグの優先順位の決定等の参考にします）も始める予定です。Engine Yard CloudからJRubyを使った（Ruby以外のライブラリや、Java、Scala、Clojureのコードをも使える）手軽なクラウド商品も発売されます。そして、漸くJRubyの本も書きます。これにはチュートリアルや、リファレンス一覧、トラブルシューティングのヒント等、JRubyを今使いこなす為に必要な事項を盛り込む予定です。&lt;br /&gt;&lt;br /&gt;素晴らしく、そしてワクワクする一年になりそうです。</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/3843383305121634010/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2010/01/mavenrakec.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/3843383305121634010'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/3843383305121634010'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2010/01/mavenrakec.html' title='大忙しの一週間。アンドロイド、Maven、Rake、C拡張、そして…'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8455118714591559121.post-3586519140347954059</id><published>2009-12-01T20:01:00.001-06:00</published><updated>2010-01-10T08:40:20.236-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JRuby"/><category scheme="http://www.blogger.com/atom/ns#" term="JVM"/><category scheme="http://www.blogger.com/atom/ns#" term="日本語訳"/><title type='text'>JRubyのJはJVMのJ</title><content type='html'>&lt;a href=&quot;http://www.engineyard.com/blog/2009/j-is-for-jvm-why-the-j-in-jruby/&quot;&gt;原文&lt;/a&gt;：トム＝エネボ&lt;br /&gt;&lt;br /&gt;現在JRubyの開発に携わっている面々は皆Ruby、Java、そして勿論JRubyを熟知している情熱的なハッカーばかりです。とは言うものの、このプロジェクトの創成に関わった者は一人も居ません。JRubyの先駆者たちはそれがいいアイディアだったと考えたに違いありません&amp;mdash;私もJRubyのことを初めて耳にした時そう思いました。ところが多くの人にとってはこれはそう自明の事では無いのかも知れません。そういう人たちは「JVMの上でJRuby書いていい事なんかあるのですか」と訊きます。僕らJRubyチームはちょっとネジが外れてるか、狂気の天才なのか、それともJVMを使うのは至極実利的な決断なのでしょうか。&lt;br /&gt;&lt;br /&gt;Javaは登場した当時、存在していたプログラム言語をちょっと良くしたような物でした。Javaはそこそこ簡単であり、かつ既によく使われていたCやC++を進化させたような物であるにも拘わらず、ハードウェアに中立なバイトコードを走らせる事の出来る仮想マシンでした。ガーベージコレクションがJavaには実装されていたので、メモリ管理やコアダンプに大して気を捕らわれなくなりましたし、加えて中々総括的なライブラリを持っていました。特に目新しい物は無かったのですが、既にあったアイディアを上手い具合に組合わせて使える物になっていたと言えるでしょう。&lt;br /&gt;&lt;br /&gt;これは私見ですが、このように二つの異なる物をJavaと言う一つのブランドで売ろうとしたSunのマーケット戦略は長い目で見ると失敗でした。この戦略では、プログラム言語とランタイムが全く同一の物であるかのように同じ名前で呼ばれる事になっていたのです。この戦略は、ランタイム（それ自体で充分に利点の有ったJava仮想マシン）にとって非常に不公平な物でした。更に、JythonやJRubyの様にJVMを基にしたプログラム言語が、プログラム言語としてのJavaとの混乱を招く事無しにJVMの良さを説明する事が出来なくなるという結果にもなりました。&lt;br /&gt;&lt;br /&gt;本稿ではJVMの良い点と悪い点について触れることにして、JVMの姿を読者が垣間見る事が出来ると良いと考えます。&lt;br /&gt;&lt;br /&gt;本題に移る前にもう一言。本稿で扱うのはSunのJVMについて私の知っている事に限っています。Sun以外からもJVMはリリースされていますし、それぞれに良さが有ります。私が以下に挙げる点の多くはそうしたJVMにも当て嵌ると思われますが、私がそうしたJVMの詳細に暗い事は断っておきます。&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;短所&lt;/h2&gt;&lt;br /&gt;完璧なテクノロジーは存在しません。JVMも勿論例外ではありません。JVM上でJava以外の言語の実装をした事のある人ならば、その苦労は解ると思います。プログラム言語実装に便利な基盤をJVMは提供してくれますが、元々はそうした用途を想定してデザインされている訳ではありません。その為、独創的な問題解決を余儀なくされる事が時としてあります。&lt;br /&gt;&lt;br /&gt;例えば、JRubyではフレームスタックの実装にヒープ領域から割り当てられたオブジェクトを使っています。融通が利くのならば、本物のフレームスタックを直接操作し、JRubyに必要なフィールドを加えるところです。JVMではフレームスタックをそこまでは操作できません。残念。&lt;br /&gt;&lt;br /&gt;他には、RubyでのFixnumオブジェクトを造る際、これらの値をボックス化してJavaのオブジェクトに内包させています。RubyのC言語での実装では単にタグの付いたintを渡すだけで済みます。もっと高速のFixnumがあれば良いのですが、Javaの原始型では一般的なリストに入れる事が出来ませんから、これを使う訳には行きません。&lt;br /&gt;&lt;br /&gt;ちょっと差し挟んで言うと、JVMの起動にはかなりの時間が掛かる事も問題です。&lt;br /&gt;&lt;br /&gt;JVMで速いコードを書かなければならない人の中には、VMの中の動きがよく解らない事に業を煮やした経験のある人も居るかも知れません。一度バイトコードをロードしてしまった後は、ただスイッチを入れて良い結果が出る事を祈るだけです。どのような結果が出るのか予測する事は難しいです。&lt;br /&gt;&lt;br /&gt;小言を並べてみました（勿論この他にも改良されるべき点は色々とあります）が、JRubyがJVMの上で実装されていると言う事に私はとても満足しています。何故でしょうか。それは…。&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;長所&lt;/h2&gt;&lt;br /&gt;&lt;h3&gt;HotSpot&lt;/h3&gt;&lt;br /&gt;先ず始めにHotSpotについて述べます。HotSpotには神秘的な物がありますが、一般に高いパフォーマンスの実現に一役買っている事は間違いありません。動的にプロファイリングを行うのは高いパフォーマンスへの近道です。HotSpotは我々などより遥かに賢く、しかも走っているアプリケーションのデータを使って最適化の一助とする事も出来るのです。&lt;br /&gt;&lt;br /&gt;HotSpotには既に最適化されているコードを非最適化する機能もあります。奇妙に聞こえるかも分かりませんが、これが高いパフォーマンスを可能にする要因なのです。HotSpotが最適化をする時、始めに最適化された部分のコードの前に簡単なガードを置いて、最適化の為に用いた前提条件が本当に満たされているのかを確認します。このガードが満たされなかったりした場合、HotSpotはこの部分のコードを非最適化します。何故これが凄いかというと、この性質の為にJVMは、最適化にとても積極的になる事が出来るからです。もしHotSpotの「勘」が当たると、その配当はとても大きいです。「勘」が外れても、今一つズレている最適化を試してみたという多少のコストを払って、後々の最適化に役立つ情報を手に入れた後、最適化していた部分を元に戻すだけで済みます。&lt;br /&gt;&lt;br /&gt;このHotSpotの働きを示すのが下のグラフです。￼&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://farm3.static.flickr.com/2500/4116632798_bffb4ecaf7_o.png&quot; alt=&quot;&quot; width=&quot;576&quot; height=&quot;432&quot; /&gt;&lt;br /&gt;&lt;br /&gt;このグラフに示すのはマンデルブロ集合を描く作業を何度か繰り返した、その所要時間です。グラフの右側でJRuby1.4.0を見ると、Ruby1.8.7を明らかに凌駕し、またRuby1.9.2preview2といい勝負をしているのが解ります。JRubyのグラフを追うと、Ruby1.8.7にテスト開始直後こそ後れを取っているものの、HotSpotがその機能を発揮するにつれて急速に追いつき追い抜いていく様が手に取るように解ります。&lt;br /&gt;&lt;br /&gt;六度目のテストでJRubyの結果が少し悪くなっています。これは先に述べたHotSpotの非最適化の結果です。七度目以降は結果が五度目程度まで回復しているのも判るでしょう。七度目以降の最適化で六度目のテストで発生した非最適化の部分を総て取り戻す事が出来たのです。&lt;br /&gt;&lt;br /&gt;HotSpotに匹敵するものを書く事は私には無理でしょう。数多くの優秀なエンジニアたちによって十年近くの歳月を掛けてHotSpotは磨き上げられました。実際、Java４、５、６でHotSpotは見事な進化を遂げました。JRubyはHotSpotを何もせずにタダで使う事が出来るだけでなく、HotSpotがアップグレードされる度にその恩恵を浴びる事が出来るのです。これはJVMを使えばこそ。完璧なテクノロジーなど無いとは言いましたが、これはかなりそれに近いと思います。これはまだ小手調べ。ガーベージコレクションに言及もしていません。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;ガーベージコレクション&lt;/h3&gt;&lt;br /&gt;Javaの開発者たちは、それこそ数世紀に値する時間を掛けて仮想マシンをデバッグし、テストし、改良してきました。15年もの間、ただガーベージコレクション（以下GC）の為だけに働くエンジニアが詰まった建物を想像してみて下さい。Java仮想マシンには沢山のガーベージコレクタが梱包されていますから、一つのコレクタで上手く行かなかったとしても、JVMではその他のコレクタを使う事が可能です。更に、コレクタを一つ一つ調節する事も出来ます。アプリケーションによってコレクタを自由に使い分ける事が可能なのです。&lt;br /&gt;コレクタの数々にはとても具合の良い属性があります。コレクタの総てはコンパクションを行いますからメモリの断片化は問題ではありません。インクリメンタルでもありますからGCが実行される際にアプリケーションが止まる時間の長さも最小限で済みます。世代別ガーベージコレクタですので、短時間しか必要のないオブジェクトは直ぐに回収されてしまいます。&lt;br /&gt;&lt;br /&gt;コレクタの幾つかは並行型でマルチコアの特性を活かす事が可能です。中には同時処理が出来るのでGCの為にアプリケーションを止める必要のないものもあります。こうした素晴らしいコレクタ等も数多のアプリケーションで既にその性能を実証済みです。JRubyではこうしたもの総てをタダで使う事が出来るのです。Java 7（及びJava 6u12）ではG1と呼ばれる新しいコレクタも登場しています。JavaのGCは今も尚改良が続いているのです。&lt;br /&gt;&lt;br /&gt;JVMにおけるGCについて良い点をもう二つ挙げます。どちらもGCの視覚化とどのように作動しているのかに関するものです。一つはJavaで使われる-J-verbose:gcというフラグです。このフラグを使用すると、いつ、どれ位のメモリを、どれ位の時間を掛けて収集したかというGCに関するイベントを総て記録してくれます。これを使うとアプリケーションにおいてコレクタが上手く作動しているかを把握する事が出来ます。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[GC 16000K-&gt;3727K(82496K), 0.0396636 secs]&lt;br /&gt;[Full GC 13021K-&gt;5802K(82496K), 0.1468975 secs]&lt;br /&gt;[GC 21802K-&gt;9769K(82496K), 0.0292348 secs]&lt;br /&gt;[GC 25769K-&gt;12535K(82496K), 0.0243674 secs]&lt;br /&gt;[GC 28535K-&gt;13136K(82496K), 0.0169928 secs]&lt;br /&gt;[GC 29136K-&gt;15498K(82496K), 0.0213308 secs]&lt;br /&gt;[GC 31498K-&gt;16911K(82496K), 0.0213301 secs]&lt;br /&gt;[GC 32911K-&gt;19413K(82496K), 0.0186457 secs]&lt;br /&gt;[GC 35413K-&gt;20207K(82496K), 0.0146396 secs]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;記録されたイベントを集計する事によってメモリの収集に全体でどれだけの時間を要したかが判りますし、もしかしたらアプリケーションが課す作業量にGCが着いて行ってない事も判るかも知れません。そうした場合、アプリケーションのデザインの見直しや、ヒープ領域の拡大などを試したりする事にもなるでしょう。&lt;br /&gt;&lt;br /&gt;もう一つはjconsoleによってJVMの動きを見る事です。jconsoleにはJVMの内部を覗く為の様々な機能（JVMの動作を操作するものも有ります）がありますが、ここで触れるのはGCの作業具合を見る事の出来る、メモリのタブです。&lt;br /&gt;&lt;br /&gt;￼&lt;img src=&quot;http://farm3.static.flickr.com/2494/4115863635_148128d48f_o.png&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;ウィンドウ右下に、それぞれの世代のメモリの使用量が緑色の棒グラフで表示されています。例えば、上の図で左から三番目の棒が空になっていますが、これはこの世代のメモリが全く回収されずに済んでしまった事を示しています。GCが上手く作動していない事の証左ですので、アプリケーションの改良を検討する必要が有るでしょう。&lt;br /&gt;&lt;h3&gt;移植性&lt;/h3&gt;&lt;br /&gt;HotSpotとGCはJavaを使える環境ならばどこでも使えます。つまり、JRubyは他の環境でもただ単に動くばかりでなく、とても上手く動くのです。このような素晴らしい環境を何もせずに手に入れる事が出来るのは素晴らしい事です。&lt;br /&gt;&lt;br /&gt;更にJRubyはちょっと変わった環境でもJavaさえあれば動きます。バグ報告の中にはOpenVMSからの物さえあります。IBMメインフレームのCP/CMSで動くJRubyの話も耳にします。こうした環境で動くというのはちょっと「ヤバい」気がします。これも偏にJVMのお陰と言えます。&lt;br /&gt;&lt;br /&gt;実際、Javaのソースコードが公開されてOpenJDKプロジェクトの発足を受けて、JVMは今後も色々なハードウェア環境へと伝播して行く事でしょう。このように、移植性という点でJVMはほぼ完璧と言えると思います。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;成熟性&lt;/h3&gt;&lt;br /&gt;JVMは開発が始まってから15年を経て、大人向け映画を観に行けるような歳ではないかと思います。JavaOneカンファレンスでは、JVMのソフトウェアとしての長寿が、子供が成人して行く様に正しく喩えられていました。過去15年にJVMの安定化と高速化と普及の為に注ぎ込まれた膨大な努力の恩恵に、JRubyは全く何もせずにあやかる事が出来るのです。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;JVMチームとの連携&lt;/h3&gt;&lt;br /&gt;JRubyとその他のJVM上で動く言語は、JVMに携わるエンジニア達にも知られています。一つ例を挙げますと、JSR292としても知られるinvokedynamicという仕様があります。この仕様は、JVM上で実装される新しい言語と、メソッド選択にJava以外の言語も念頭に入れる必要が有る事を明文化するものです。JVMが、JRubyのようなプロジェクトにとってより良いプラットフォームになりたいと考えていると言う事は大変良い事です。&lt;br /&gt;&lt;br /&gt;MLVM（多言語仮想マシン）と呼ばれるプロジェクトではJVMでどのフィーチャが採用されるべきかの情報交換が行われています。そこは、野心的なデベロッパがJVMでのフィーチャの実装を試す機会を与えてくれます。JVMのエンジニア達も直接関って、様々な提案もしてくれます。これは新しいJVMフィーチャの培養器と言った感が有ります。&lt;br /&gt;&lt;br /&gt;この二つの点は、JVMエンジニア達が、視野を広げ、またユーザーの声に耳を傾けている事を示している事の現れであるということで特に喜ばしいです。&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;まだまだ続きます&lt;/h3&gt;&lt;br /&gt;JVMはテクノロジー展望の一部となりました。オラクルによるSunの吸収合併と、それに伴ういざこざをめぐって、中には首を傾げるようなニュースも飛び交っていますが、真相は至ってありきたりです。オラクル、IBM、HP、SAP等々、多くの巨大な企業がJVMで動くミドルウェアの創造に莫大な投資をしているので向こう十年程度でJVMへの拘わり方が変わるとは考え辛いです。&lt;br /&gt;&lt;br /&gt;これにより、JRubyの更なる性能の向上が見込めます。加えて、Rubyような言語、或いはRuby on Railsへと市場を導く機会がJRubyには有ると言えます。JRuby開発チームは全力でRubyist諸氏のRubyランタイムへの要望を満たす努力をしています。同時に我々は、Javaを使う人々に、アプリケーションによってはRubyがJavaに優り、しかも使用するプラットフォームを換える必要のない言語である事を伝えているのです。</content><link rel='replies' type='application/atom+xml' href='http://jruby-ja.blogspot.com/feeds/3586519140347954059/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://jruby-ja.blogspot.com/2009/12/jrubyjjvmj.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/3586519140347954059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8455118714591559121/posts/default/3586519140347954059'/><link rel='alternate' type='text/html' href='http://jruby-ja.blogspot.com/2009/12/jrubyjjvmj.html' title='JRubyのJはJVMのJ'/><author><name>Hiro</name><uri>http://www.blogger.com/profile/16816839179553173311</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ZM-qyl_dHwNDu6TWrnq_Y-Ja5JS9VylRUQ-kSvzqOBHxlTnNVkMGQA3b2zxz_wMiqmTfZvoHhfKqmN-bGS32OFaGWnRLKCWK6aTj0xZ9cndQkk4BPjMBuKrNSNLB5w/s1600-r/40e5e9fe36a1f85166493faac2c17499.png'/></author><thr:total>0</thr:total></entry></feed>