Adsenseリンクユニット

2013年6月9日日曜日

.NET リソースリークをOS標準のソフトで直ぐに見つける方法

.net frameworkでアプリケーションを作成すると、C、C++の経験者には基本の”き”であるメモリの開放処理をどこに書けばいいのだろうと思ったことはありませんか。

.netアプリケーションをプログラミングする際に、javaとかでもそうですが、オブジェクトの開放処理を記述しないコーディングになり、一抹の不安に駆られることがあると思います。

 メモリリーク、リソースリークが大問題を引き起こすことを今までの経験から分かっているからなんですね。

.net や javaのオブジェクトはスコープを抜けた際に勝手にメモリ解放の対象になり、GCとよばれるガーベージコレションがこれまた勝手にメモリが足りなくなってきたと判断したタイミングでメモリを開放します。

プログラマーからすると記述しなくても良いので、メモリ解放の記述漏れがなくなることはとてもありがたいことです。

ですが、スコープを抜ければ、リソースが勝手に開放されると思っている方は、とても危険なバクを埋め込んでしまっているかもしれません。

リソースの開放に関しては、明示的にプログラミングする必要があるのです。


リソースとは、単純にアプリが獲得したピープメモリではなく、OSが管理しているオブジェクトです。代表的な例はファイルです。ファイルにアクセスするには、OSが管理するオブジェクトと橋渡しをするハンドルを仲介しない限り扱えないようにOSが設計されているのです。

C,C++では当たり前のようにハンドルを意識せざるを得ない、プログラミングでハンドルの記述をしないとファイルアクセスできなかったので、否が応にもハンドルの存在が分かってしまうのですが、昨今の便利になった.netやjavaだとハンドルってなんですか、そんなの意識する必要性そのものがあるのですかと思う方も多いと思います。

もちろん、ハンドルという言葉を無理に意識することはないです。ですが、リソースリークが発生して困っているならばもう一歩踏み込んでハンドルを理解する必要があります

それでは、リソースリークが起こるとどんな現象、問題が引き起こされるのでしょうか。私もそうですが、痛い思いをして初めて事の重大さに気づくことってありますよね。

お客様にご迷惑をかけてしまうことがもっとも痛いことですよね。リソースリークをしっかりテストしていないと、後になって深刻な問題を引き起こすことになります。プロセスダウンします。

そして、お客様に提供した頃に気づくようでは、ソース修正の範囲が膨大になってしまう可能性大です。

リソースってなんなの?から始めましょう。OS標準のソフト、タスクマネージャを使えば、小難しいツールを使わなくても、リソースリークが発生しているかどうか簡単に判別できるんですよね。

「ALT+SHIFT+DEL」で表示するか、あるいはタスクバーを右クリックで出てる「タスクマネージャの起動」から表示される下記の画面です。


タスクマネージャでリソースリークを検出する方法

 デフォルトの表示列では、どのプロセスがどれくらいメモリを使用しているのか分かりますが、リソースリークを調べたい場合は次の手順で表示列を増やします。

  1. 「プロセス」タブをクリックする。
  2. メニューバーの「表示」をクリックし、「列の選択」をクリックする。
  3.  「ハンドル」、「USERオブジェクト」、「GDIオブジェクト」にチェックを付けてOKをクリックする
 
ハンドル、USERオブジェクト、GDIオブジェクト

 これで、ハンドル数、USERオブジェクト数、GDIオブイェクト数がプロセス毎に現在どれだけ使用されているか一目で分かります。

.net で注意が必要なのは、リソースを消費する画面つまりFormやDaialogのように画面表示するオブジェクトです。画面に表示されるということは、リソースを消費しOSが画面上に表示を行なっているわけです。

.netでリソースを開放する方法

 .net ではリソースの開放はdisposeで行います。記述方法は2種類あります。私が好きなのは後者です。

分かりやす方法

画面オブジェクトに対して直接disposeを記述します。ファイルアクセスを例にすると下記のような記述になります。

public void Func() {
    FileStream fs = new FileStream("test.txt", FileMode.Read);
    try {
        StreamReader sr = new StreamReader(fs);
        try {
            // 処理する
        }
        finally {
            if (sr != null) {
                sr.Dispose();
            }
        }
    }
    finally {
        if (fs != null) {
            fs.Dispose();
        }
    }
} 
参考サイト:C# Tips -usingを使え、使えったら使え(^^)-


漏れがなくとても美しい記述スタイル

using句を利用した記述方法、下記の記述を見ても分かる通り、とてもスッキリしています。でもリソースを開放する命令であるdisposeの記述はいらないのか?と疑問に思いますよね。

using句ブロックを抜ける際に、using句で生成したオブジェクトに対してdisposeを勝手に実行してくれるのです。記述漏れを防ぎながら、コードもスッキリしているのでusing句はとても気に入っています。
public void Func() {
    using (FileStream fs = new FileStream("test.txt", FileMode.Read)) {
        using (StreamReader sr = new StreamReader(fs)) {
            try {
                // 処理する
            }
            catch () {
                // 例外処理
            }
        }
    }
}
参考サイト:C# Tips -usingを使え、使えったら使え(^^)- 

まとめます。.netはメモリを自動開放してくれるがリソース開放は明示的に記述する必要があります。後からハマる前にコーディング規約にしっかりとリソース開放してくれるusing句の記述を徹底し、安全なアプリケーションが出来上がることを願います。

0 件のコメント:

コメントを投稿

スポンサードリンク