ソフトウェアの開発をしていると、開発後半になってあらわになる問題があります。
それは、メモリリークなどのリソースがリークする問題です。
問題の原因が分かると、「あー、解放が漏れていたのはここか。」と
単純な誤りであることが多いですが、解析にはかなりの時間を要します。
本記事では、なぜメモリリークが起こるのか、そして避けるための方法を解説します。
メモリリークはなぜ起こる?
先に結論を書くと、メモリリークが起こる原因はズバリ以下となります。
解放するタイミングを考えなければならないから
メモリ確保を行ったら、解放するタイミングを考えて解放する、というのが設計の王道です。
「メモリ確保」と「メモリ解放」、ペアでの設計が必要と考えられています。
ですが、様々な複雑な処理や異常処理、エラー処理などを書いているうちに条件が複雑になり、
ペアであるはずの「メモリ解放」の処理が漏れてしまい、リークが発生するのです。
メモリリークとは?
いまさらですが、用語について少し触れておきます。
メモリリークは、Wikipedia で以下のように説明されています。
メモリリーク(英: memory leak)とは、プログラミングにおけるバグの一種。プログラムが確保したメモリの一部、または全部を解放するのを忘れ、確保したままになってしまうことを言う。プログラマによる単純なミスやプログラムの論理的欠陥によって発生することが多い。

なぜメモリリークが問題となるのか
メモリリークが起きると何が問題となるのでしょうか。
ここでは、大きく2つの問題をお伝えしておきます。
空きメモリの枯渇
メモリリークが頻発すると、当然ながらメモリの空き領域が減少します。
実行中のプログラムが必要なメモリ領域を確保できなくなり、正常に動作しなくなります。
また、OSを搭載している場合は、空きメモリが少なくなると OOM Killer によって
強制的にプログラムを終了させられる場合もあります。
サーバ側のソフトウェアや、長時間稼働する常駐プログラムの場合、
メモリリークは致命的な問題となります。
パフォーマンスの低下
OSを搭載している場合には、メモリの空き領域が減少することによりスワップ動作が増えます。
スワップ動作とは、ストレージを一時的なメモリとして使用するため、
メモリの内容をストレージに退避させたり、ストレージからメモリに戻したりする動作です。

また、DMAなどで連続した物理メモリを確保する際、マイグレーション処理などが動作して
メモリを確保します。空きメモリが少なくなるとメモリの引っ越しが頻繁に発生するため、
こちらも性能低下につながります。
メモリリークの例
malloc(3) と free(3)
動的メモリ確保、メモリ解放を行う標準Cライブラリの関数です。
malloc(3) でメモリを確保し、free(3) で解放します。

malloc / free を内部で使う他の関数として、以下のような組み合わせもあります。
- pthread_cond_init(3) と pthread_cond_destroy(3)
- pthread_attr_init(3) と pthread_attr_destory(3)
- strdup(3) と free(3)
new と delete
C++ でクラスのインスタンスを生成したりする際に利用するオペレータです。
new でメモリを確保し、delete でメモリを解放します。

インスタンスに必要な領域を確保後、内部関数アドレスや初期値がセットされます。
メモリリークを避けるための方法
C++では、メモリリークの危険性を低減する方法として、
スマートポインタと呼ばれる仕組みが用意されています。
詳しくは「スマートポインタとは? C++での使用方法とメリット」に記載していますが、
確保したメモリを、適切なタイミングに自動で解放してくれる仕組みです。
こちらをCHECK
-
-
スマートポインタとは?C++での使用方法とメリット
C++ではポインタを使ってメモリの内容を書き換えたり、同じメモリを参照したりします。しかし、メモリリークや解放済みのメモリにアクセス、メモリの2重解放、などの問題に悩まされます。本記事では、これらの悩みを解決するスマートポインタについて紹介します。
続きを見る
大規模なOSSである「Android」や「Chrome」、「Qt」などでもメモリリーク対策として利用されており、
C++言語を採用する際には必ずと言っていいほど使用されています。

おわりに
いかがでしたでしょうか。
メモリリークに悩まされている方の解決策として、本記事が参考になればうれしいです。