プログラミング言語のメモリ管理について

最近勉強したプログラミング言語のメモリ管理について紹介する。

参考にした本*1

そもそもなぜメモリ管理が必要なのか

  • 不要なメモリ領域を開放する。必要な時にメモリ領域を割り当てることをメモリ管理と呼ぶ
  • 不要なメモリが開放されないと、例えばwebサーバーのような長期間動くプロセスでは、利用するメモリがどんどん増えていき、コンピュータ自身の動作を不安定にする。メモリリークと呼ばれる
  • 必要なメモリ領域が確保されていない(例えば、開放された後に参照してしまう)と、何が起こるかわからない状態になる。エラーで落ちてくれるかもしれないし、アクセス許可をしていない値にアクセスしてしまうかも知れない。

 

代表的なメモリ管理方法とその詳細

  • 静的変数
    • プログラムを開始する前に必要なメモリ領域をすべて決めてしまう。
    • すべての変数がプログラムの開始から終了まで生存する
    • メリット
      • すべての変数のメモリが確保されており、開放されることもないのでメモリ管理の最低限の目的が達成される
    • デメリット
      • プログラム起動後にメモリ容量を変えることができない
  • 自動変数
    • 変数にスコープを設定して、それに従いメモリ領域を開放する
      • メリット
      • デメリット
        • 開放された後のメモリ領域にアクセスしてしまうことが在る
  • メモリの手動確保、開放
    • C,C++ 
    • プログラム作成者が任意のタイミングでメモリの確保、開放を行う
    • メリット
      • メモリの確保、開放のタイミング、その大きさを自由に決めることができる
    • デメリット
      • 管理が複雑。間違って2回開放してしまった場合などにプログラムをクラッシュさせてしまう。
      • ヒープを使うので、実行コスト大きい
  • スマートポインタ
    • C++
    • 参照カウントなど、既存のポインタにメモリ管理に有用な機能をもたせたポインタのこと。
    • メモリ管理に関する危険性を低減が期待できる。
    • 例えば、自分への参照が無くなった時に自動でメモリを開放することにより メモリ解放を手動でしなくても良くなっている 
      • メリット
        • 自動変数と手動確保の良いとこどりで、自由に確保、開放のタイミングを決めることができ、メモリリークなどが起きる可能性は低くなっている。
      • デメリット
        • 危険性が完全に無くなるわけではなく、例えば循環参照が起きると、開放されなくなる
        • 手動と同様にヒープを利用するので実行時コストは高くなる
  •  ガベージコレクション
    • Java, Go, Python
    • 自動で必要、不要を判断してメモリの確保開放を行ってくれる
    • メリット
      • 明示的に確保、開放を支持しなくても良い
    • デメリット
      • 必要、不要の判断に実行時コストがかかる
      • プログラム作成者がコントロールできないプログラム(ガベージコレクタ)が動くことになる
  • Rustのメモリ管理
    • Rust
    • 以下の3つのルールをしいている
      • 変数への参照が、参照先の値よりも長生きしない(参照先のスコープの外で使われない)ようにしている
      • 値を代入すると所有権も渡される(代入元の変数は使えなくなってしまう)
      • 可変参照は1つしか存在できない
    • メリット
      • GCとは異なり実行時に負荷がかからない方法でメモリ管理の危険性を(完全ではないが)回避している
      • プログラム自体のパフォーマンスが期待できる
      •  
    • デメリット
      • 複数の可変参照の作成にコストがかかる
        • できないことはないが、実行時オーバーヘッドがかかる
      • unsafe句以外でも、メモリリークが起きるような記述ができる

まとめ

色々なメモリ管理方法があるが、システムプログラムをかくならRustの方が他の言語よりもメンテナンス性、パフォーマンスの面で1段階上にいるとおもう。

 

*1:Software Design 2021年9月号