そもそもメモリリークってなに?
メモリリークの調査方法について知りたい
こんにちは。文系出身で今年8年目エンジニアになる佐藤です。
皆さんはC#でプログラミングをするとき、メモリリークについて気にしていますか?「そもそもメモリリークってなに?」という初心者の方も多いのかもしれませんね。
特にC++などの言語を習得後、C#を学習し始めたという方はリソースの開放について気になっていることでしょう。
この記事では「メモリリークとは何か?」という基礎的な部分から、
- C#でメモリリーク回避方法
- 調査するためのツールを
紹介していきます。
メモリリークの回避方法をとにかく早く知りたいという方は、目次から各項目へ飛んでいってみてくださいね。最初から読むと、メモリリークの基礎から学習していける内容になっていますよ。
それではさっそく始めていきましょう。まずは、メモリリークの概要についてです!
メモリリークとは?
この章では、そもそもメモリリークとは? という基礎的な部分を解説していきます。
メモリリークが起きてしまう原因
メモリリークとは、プログラムで使用したメモリの解放忘れが原因でメモリの空きが減ってしまうという現象です。
メモリとはなんぞや? という方に向けて更に簡単に説明していきます。
よく、メモリとは「パソコンの作業机」と呼ばれます。プログラムは、その作業机の一部を「ここ使うので!」と占領することで動作できているのです。
そしてプログラムが終了するときに「ここもう使って大丈夫です!」と占領していた部分を空けるように開発者がコーディングする(「リソースの解放」と呼びます)という流れになっています。
占領していた部分を空ける命令を入力し忘れたなどの理由で、メモリの領域を空けてもらえないときは? その場合では次に動くプログラムは残りの範囲で動作します。
これが繰り返し行われたら、作業机の空きがどんどん少なくなってしまいますよね。これがメモリリークです。
メモリリークするとどうなる?
メモリリークが起こると、先程説明したようにパソコンの作業机はどんどん狭くなっていきます。処理できる量や速度がどんどん遅くなっていき、最終的はパソコンが動かなくなってしまうんです。
自分だけしか使っていないパソコンであれば再起動すれば元に戻ります。ですが、停止できないシステムが動いているため再起動が簡単にできないパソコンで起こっていたらどうでしょう? 非常に大きな問題になってしまいますよね。
メモリリークが起こると良くないということがお分かり頂けたでしょうか。エンジニアはメモリリークが起きないよう、リソースの解放にはかなり気を配ってプログラミングしていたんですね。
なんともなかったよ?
そう思ったあなた、じつはC#が陰で頑張ってくれているんです。次の章で詳しく解説していきます。
C#でメモリリークする可能性について
この章では、C#でメモリリークが起こる可能性について解説していきます。
C#はメモリリークしにくい言語
もしかしたら初心者の方は、先程のメモリリークの説明を聞いて「こわい、どうやったら回避できるの…」と少し不安になったかもしれませんね。また、「リソースの解放なんて意識してなかったよ」という方も多いでしょう。
じつは、C#はメモリリークが起こらないよう自動でリソースの解放が行われる仕組みが備わっているんです。
これをガベージコレクション(GC)と呼びます。
C言語系は、リソースの解放を開発者自ら意識して行わなければなりません。そういった不具合の原因を未然に防ごうとC#やJavaではGCが備わっています。
次に、ガベージコレクションの仕組みを見ていきましょう。
ガベージコレクションとは?
ガベージコレクションは、もう必要ないなと判断したリソースを自動的に解放してくれる仕組みになっています。
「いままでリソースの解放なんてやったことないよ…?」と不安になっていた方も、じつはGCが解放してくれていたので全く問題なかったという事なのです。安心してくださいね。
皆さんが意識してなくても、C#が自動でリソースの解放をしてくれるため安全にプログラミング出来るという訳なんです。
しかし「じゃあC#ではメモリリークは起こらないのか」という訳にはいかないんです…
しにくいけどC#でもメモリリークする可能性がある
ガベージコレクションは「もう必要ないな」と判断した結果リソースの解放を行ってくれるものです。
「これはずっと必要だよ!」と開発者がコーディングしていた場合には、ガベージコレクションも自動的にリソースの解放をしてくれません。
C#でメモリリークは起こりにくいが、コーディング次第では起きてしまう可能性がある。という事なんです。メモリリークを更に強固に防ぐ為にも、次の章で紹介する方法を使ってプログラミングしてみましょう。
メモリリークを未然に防ぐ方法
この章では、メモリリークを防ぐための手段を紹介していきます。
リソースをしっかり解放する手段がある
C#では開発者が意識してリソースを解放できるように「IDisposableインターフェース」と「usingステートメント」という手段を用意しています。
IDisposableは、自身で作成したクラスなどに実装することで、次に紹介するusingステートメントを使えるようにするインターフェースです。
usingステートメントは、Disposeメソッドを自動的に呼び出してくれる記述形式なのでfinallyブロックなどにcloseの命令などを入れなくても自動でリソースを解放してくれます。
Disposeメソッドとは、リソースの解放に関する命令を記述するメソッドです。さっそく使い方をサンプルコードと一緒に見ていきましょう。
IDisposableとusingの使用方法
まずは、usingステートメントの記述方法です。
using (FileStream fs = new FileStream("test.txt", FileMode.Open)) { }
普段ならFileStreamをクローズ命令するを書く必要がありますが、このように記述すると4行目を越えた瞬間Disposeメソッドが自動的に呼び出されリソースが解放されます。これなら、書き忘れてメモリリークする心配がありませんよね。
usingステートメントに関して詳しく解説している記事がありますので、使い方をもっと詳しく知りたいという方はこちらを確認しながら実践してみてください。
IDisposableはインターフェースなのでクラスに実装します。Disposeメソッドの実装を強制するインターフェースになっているため、自作のクラスでもusingクラスを使用できるという仕組みです。
次のコードは「作業用のテキストファイルを作り、最後は必ずそのテキストファイルを削除するクラス」のサンプルです。
using System; using System.IO; namespace Sample { //IDisposableを実装してみる自作のクラス class TextFile :IDisposable { private string filepath; public TextFile(string path) { //テキストファイルを作る filepath = path; using(StreamWriter sw = new StreamWriter(filepath)){} } public void Dispose() { //作ったファイルを削除する File.Delete(filepath); } } class Sample { static void Main(string[] args) { //TextFileクラスを使う using (TextFile tf = new TextFile(@"C:satotest.txt")) { Console.WriteLine("作業用ファイルの有無:" + File.Exists(@"C:satotest.txt")); } Console.WriteLine("作業用ファイルの有無:" + File.Exists(@"C:satotest.txt")); Console.ReadKey(); } } }
自作したクラスでもusingを使ったリソースの解放が出来ているのが分かりますね。
IDisposableとインターフェースについて詳しく解説している記事がありますので「インターフェースって何?IDisposableについて詳しく知りたい」という方は次の記事をぜひご覧ください。
最後に、メモリリークを調査するためのツールを紹介します。
メモリリークを調査するためのツール
実は、visual studioにはメモリリークを調査するための「メモリ使用量ツール」が存在しています。
⇨ Microsoft
メモリ使用量診断セッションを使用すれば、メモリ使用量の監視が出来ます。
プログラムを動かしていく中でメモリの使用量が増え続けている、減らない、ということであればメモリリークが起こっている可能性がありますので、該当のオブジェクトでリソースの解放忘れがないか確認してみましょう。
まとめ
C#でメモリリークが起こる可能性、回避方法などを解説しました。
GCでリソースの解放が自動で行われているとはいえ、気を付けておいて損はないので今回学習した内容をしっかり覚えてプログラミングをしましょう。
それでは、次の解説で!