トップ > Fortran >
割り付け配列と配列ポインタの違い | 構造型と割り付け配列

5-6. メモリーリーク

メモリーリーク

再び前節のプログラムを見てください。

program alloc_ptr_test2
  implicit none
  integer, pointer :: a(:)
  integer, pointer :: p 

  allocate(a(10))
  a(:) = 1
  p => a(1)

  allocate(a(10))
  a(:) = 2

  print *, p  !=> 1
end program

1の成分で初期化された無名の割り付け配列は、配列ポインタaとはプログラムの終わりの所では結合していません。

    a(:) -> |2|2|2|2|2|2|2|2|2|2|
            |1|1|1|1|1|1|1|1|1|1|
       p-----^ 

では、どうやったら配列ポインタとの結合が切れた無名配列を解放できるでしょうか。

結論から言うとこれは不可能です。
このように解放できなくなった変数が発生することを、通称メモリーリークと言います。

メモリーリークは致命的なエラーには分類されませんが、放置して長くプログラムを走らせていると徐々に必要なメモリが増大し、最後にはメモリが確保できなくなって、プログラムを止めてしまいます。

割り付け配列の自動解放

配列ポインタではメモリーリークが発生する可能性がありますが、割り付け配列ではあるのでしょうか。

次のプログラムを見てください。

subroutine alloc_ptr_test3
  implicit none
  integer, allocatable :: a(:)

  allocate(a(10))
end subroutine

この手続きの終わりで割り付けた配列はどうなるのでしょうか。
手続きの最後にDEALLOCATE文で解放しないと、メモリーリークが起こってしまうのではないかと心配する人もいると思います。

安心してください。
手続きで定義された割り付け配列はSAVE属性がない限り、手続きの終わりで自動的に解放されます。

まとめると割り付け配列は、

以上より割り付け配列ではメモリーリークが発生する危険性はありません。

ただし、これはFortran 95の標準から言えることであり、実際にメモリーリークが起こらないかというと例外もあります。
たとえば、いくつかのFortran 90コンパイラでは再割り付けの前に解放しなくてもエラーを発生させません。
またFortran 90の標準では手続きの終わりで自動的に解放されません。

いまどきのFortran 90コンパイラで割り付け配列の手続き終了時の自動解放をサポートしていないのは見たことがありませんが、気になる人はDEALLOCATE文を手続きの最後にかいておくことをお勧めします。

自動解放の失敗例

割り付け部分のサブルーチン化でやりがちな失敗が以下のプログラムです。

module m
contains
  subroutine alloc(array)
    integer, pointer     :: array(:)       ! 配列ポインタ
    integer, allocatable :: local_array(:) ! ローカルな割り付け配列
  
    allocate(local_array(10))
    array => local_array      ! エラー、ローカルな割り付け配列への割り付けは手続きを出ると未定義になる
  end subroutine
end module

program alloc_test
  integer, pointer :: array(:)

  call alloc(array)
end program

このプログラムはモジュール手続き中の変数で配列を確保して、それを指し示すポインタを返すつもりで書いたプログラムです。

これはコンパイルエラーになりません。だからこそ絶対にやってはいけません。なぜなら

手続き中の割り付け配列変数はALLOCATEされても、手続きを出た瞬間に自動解放で無効になる

からです。
手続きを出た瞬間に配列が解放されて、その領域が上書きされても文句は言えません。
このようなプログラムを組むと、後でその配列の部分が勝手に破壊されたりするので、不可解なバグの原因になります。

手続き中の変数をポインタで参照したままにしないことは、C言語をやったことのある人にとっては当然の鉄則です。
しかし、C言語から入った人は動的に確保した配列まで解放されるとは思っていないので、かえってこのあたりのバグをいれやすいです。気をつけましょう。


縦々横々 じゅーじゅーおーおー 割り付け配列と配列ポインタの違い | 構造型と割り付け配列