.NET開発者中心 厳選ブログ記事

3つの視点でネイティブと.NETの適材適所を考察
―― 「C#たんっ!」より ――

C#たん
2012/01/31

「.NET開発者中心 厳選ブログ記事」シリーズでは、世界中にある膨大なブログ・コンテンツの中から、特にInsider.NET/.NET開発者中心の読者に有用だと考えられるブログ記事を編集部が発掘・厳選し、そのブログ記事を執筆したブロガーの許可の下、その全文を転載・翻訳しています。この活動により、.NET開発者のブログ文化の価値と質を高め、より一層の盛り上げに貢献することを目指しています。

本稿は、ブログ記事「C#たんっ!: ネイティブと.NETと」に簡単な校正・加筆を行ったうえで転載したものです。

 ネイティブ vs. .NETと、対立的に描かれることも多いですが、実際には、相補的な関係にあります。

 そう、それは例えるなら、こんな感じのお付き合い。

 「一見、お前ら何やってんだ」という感じに見えますが、前衛×後衛がはっきりと分かれているだけで、良いお付き合いができる関係にあるのです。

 ここでいう「ネイティブ」は、実CPUのネイティブ・コード(を直接出力するC++などの言語)のことです。

ネイティブか.NETか、それが問題だ

 (この見出しは)うそです。

 「AかB、どっちがいい?」という質問の答えは、往々にして「両方」です。残念ながら。毎回毎回、「これ1つで全てを解決!」みたいな銀の弾丸を期待しては、毎回毎回、夢物語に終わるのです。

 アプリは.NET(C#とか)で書いた方が楽。それは間違いないです。一方で、インフラ的なところ、データベースやらGUIフレームワークみたいなものの内部は、ネイティブで書いた方が楽。場合によってはネイティブで書かざるを得ません。極度のパフォーマンスが必要な場面では、.NETで書く方がかえって大変になることが多いです。

 結局、「適材適所」としか言いようがないです。では、それぞれ、どこが適所なのでしょうか? それぞれの利点/欠点をまとめてみましょう。

3つの視点

 .NET Frameworkが持っている性質を3つに分けて考えてみます。

(1)共通型システム
(2)メモリ管理の自動化
(3)CPU独立な中間言語

 ネイティブと.NETは、アンマネージ・コードとマネージ・コード(managed: .NET Frameworkに管理されているという意味)という対立構造で描かれることが多く、マネージ・コードが持つ、これら3つの性質はまとめて説明されることが多いです。

 しかし、これら3つの性質は互いに独立(にもできる)概念です。例えば、共通型システムを持つことはネイティブな言語でも重要だと思いますし、メモリ管理が手動な中間言語があってもいいと思います。

(1)共通型システム

 .NETのライブラリは、C#からでもVB(Visual Basic)からでも、何なら、PowerShellやIronPythonなどからでも共通利用可能です。これが可能なのは、共通型システム(common type system)という、型の取り扱いに関する規格を持っているからです。

一番大事

 個人的には、.NETの性質の中で一番大事なものだと思います。

 今はもう、ライブラリやフレームワークなくしてアプリなんて作れません。.NETやJavaを見てのとおり、標準ライブラリの時点で膨大な量のライブラリがあり、さらに、第三者提供のライブラリも山ほど見つかります。

 これだけ大量のライブラリがあって、それらを使いこなすことが要求されると、プログラミング言語自体を覚えることよりも、ライブラリを覚えるコストの方がはるかに大きいです。逆にいうと、ライブラリさえ共通利用できるなら、言語の違いなんて微々たるものです。

Windows 8

 次期Windows 8(コード名)で、共通型システムの適用範囲が広がります。.NETのメタデータ規格を流用して、ネイティブやJavaScriptでも型を共通利用できるようになります。

 Windows 8では、今までのWPFのようなものが、ネイティブ・コードで書き直されました。しかし、新しい共通型システムのおかげで、.NETから見ると、今までと何の変わりもなくWPFと全く同じ感覚で使えます。

利点/欠点 まとめ

○共通型システムの利点

  • ライブラリの学習が楽になります
  • 実行に関係ないメタデータを持つことで:
    • 動的コード生成ができる
    • セキュリティに関する情報も持てる

○共通型システムの欠点

  • メタデータの分、プログラム・サイズが大きくなる
  • 標準規格に縛られる
    • .NETとかJava仮想マシンの型システムはOOP(オブジェクト指向プログラミング)前提なわけですが、ほかのパラダイムを使いたいときにネックにならないか?
    • Java仮想マシンはジェネリックや値型を持っていないのがけっこうなネックに
    • 「nullを許さない参照型」が欲しかったりするけども、今から追加するにはコストが大きすぎる

(2)メモリ管理の自動化

 あなたのやりたいことはメモリ管理ですか?

 メモリ管理自体が目的になることはないわけですが、その割に、メモリ管理は非常に大変です。

 今となっては、むしろ、メモリの自動管理機構を持っていない言語の方が珍しくなってしまいました。

マネージ・ヒープ

 .NETのように、ガベージ・コレクション(garbage collection)機能によって管理されたメモリをマネージ・ヒープ(managed heap)といいます。

 マネージ・ヒープは以下のような性質があります。

  • マネージ・ヒープは、全体としてのスループット的には非常に性能がいいです
    • ヒープ(動的なメモリ確保)が必要なら、素直にマネージ・ヒープに任せる方がいいです
    • ただ、処理負荷が、ある1点に集中してしまうことがあります
  • 手動管理ではそもそもヒープを使わないような最適化が可能ですが、自動管理の場合はそういう最適化がしにくいです
    • 下手なことをすると、ガベージ・コレクションの仕事を阻害して、かえって遅くなります
  • マネージ・ヒープは、確保できる物理メモリ量が多めにあるときに良い性能を発揮します
    • 省メモリ環境は苦手です
    • 物理メモリを目いっぱい使うようなキャッシュ処理は苦手です

管理外リソース

 さて、プログラムで使うリソースは、何もメモリばかりではありません。ファイルやグラフィック、ネットワーク接続などもあります。これらのリソース管理は、結局、自前で行う必要があります。

 最悪、メモリの自動解放のタイミングで一緒にこの手のリソースを解放してもいいのですが、無駄に多くのリソースを使ってしまうので、場合によってはかなり性能を落とします。

管理されていてもメモリ・リーク

 ガベージ・コレクションは、「誰からも参照されていないゴミを見つけて解放する」というような仕組みで動いています。従って、「本当はもう不要になったのに、誰かがずっと参照しっぱなし」みたいなことをすると、結局、不要なメモリが残り続けます。

 イベント駆動なプログラム(GUIアプリなどだと、イベント駆動がほぼ必須)では、参照関係が複雑になりがちで、誰が誰を参照しているかが分からなくなりがちです。参照を外し忘れてメモリ・リークしてしまうことも多いです。

利点/欠点 まとめ

○メモリ自動管理の利点

  • やりたいことに集中できる
  • セキュリティ・ホールを作りにくい
  • ヒープの性能(スループット)がよい

○メモリ自動管理の欠点

  • メモリ以外のリソースの管理は結局、自前
  • 自前管理との相性があまりよくない
  • 部分的に自前管理で性能上げようとすると逆効果になりがち
  • そもそもヒープ利用を避ける最適化もしづらい
  • ガベージ・コレクション発生時に一時的に応答が悪くなることがある

(3)中間言語

 昨日のブログ記事の投稿で、中間言語(IL: intermediate language)を説明しました。要は、いったんCPU非依存な形式でプログラムを配布しておいて、実行時に実CPUのネイティブ・コードに変換します。

クロスCPU

 .NETは、いろいろな環境で動くことを想定しています。デスクトップ向けのWindows以外にも、Windows Phone 7はARMですし、Xbox 360のCPUはPowerPCベースです。SilverlightにはMac版もあります。今は、Monoもあるので、Linuxなどでも動きます。

 同じOSであっても異なるCPUに対応しないといけません。いわゆる32bit版(x86)と64bit版(x64)がありますし、次期Windows 8ではARMプロセッサにも対応します。

 アプリを作る側からしても、それぞれのCPU向けにコンパイルして配布するのはけっこう面倒です。

 コンパイラを作る側の視点だと中間言語の重要性はもっと増します。中間言語を介するのであれば、プログラミング言語(C#とかVB)の専門家と、CPUごとの最適化の専門家に分かれて作業ができます。プログラミング言語の専門家は中間言語を作るところまで、CPU最適化の専門家は中間言語から先だけ気にすればよくなります。

セキュリティ

 中間言語は、命令がかなり高級で、セキュリティ的な検証がしやすいです。.NETの場合は、署名を入れて検証したり、メタデータに必要な権限の情報も入れたりしておけるので、非常に強固なセキュリティ保証ができます。

性能の良し悪し

 平均的な状況では、.NETのコードでもネイティブの8〜9割の性能が出るといわれています。ただ、本当に状況次第です。ネイティブの方が数倍速くなる状況もありますし、.NETの方が速くなることもあります。

 標準C++の範囲のコードならともかく、インライン・アセンブラを使ったCPU依存の最適化を実施すると、明らかにネイティブの方が速くなります。そこまでコストをかけてでも性能が必要な場合、.NETは使えません。

 また最近だと、大規模データ処理を、GPUを使って行う手法(GPGPU: General-purpose computing on GPU)などもありますが、これも過度に環境依存になるので、.NETからは直接活用しにくいです。

利点/欠点 まとめ

○中間言語の利点

  • 配布が容易
    • 1バイナリ・ファイルで、いろいろなCPU向けに配布可能
  • 命令長が短く、プログラム・サイズが小さくなる
  • セキュリティ保証しやすい

○中間言語の欠点

  • 多少、性能が犠牲になる
    • コード実行の途中にJITが挟まる
    • CPUに過度に依存する(SIMD系命令やGPGPUなどの)最適化が無理

 今回の転載記事は、2011年12月に多数の技術系ブログで開催された「Advent Calendar 2011」(参考:「@IT Java Solution: 師走を楽しもう。技術系アドベントカレンダーの魅力とは」)の1つである「C#たんAdvent Calendar 2011!」の中から、1つのブログ記事を厳選したものです。C#たんAdvent Calendar 2011!では、このほかに、下記のような記事の人気が高かったそうです(人気順)。

 本稿のブログ記事以外にも、Advent Calendar 2011の各ブログ記事の中には有用なものが多数あります。興味のある方は、「Life like a clown: Advent Calendar 2011 (jp) 開催予定リスト」などのAdvent Calendar 2011のリストから、興味のある技術分野を探して、そのブログ記事に目を通してみてください。End of Article

【筆者プロフィール】
C#たん

 自分のことは棚に上げて、「萌えればいいってもんじゃないですよ?」が信条。ソフトウェアに求められる要求の高度化とともに大きくなる開発者への負担を、開発ツールやフレームワーク、時には萌え力を頼りに軽減できないかと考えています。単なる萌えキャラだと思ったか? ガチだよ、ガチ!


インデックス・ページヘ  「.NET開発者中心 厳選ブログ記事」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH