LoginSignup
1
2

More than 3 years have passed since last update.

Fortranでメモリリーク?-どこまでも増えていくメモリ使用量(原因不明)

Last updated at Posted at 2021-03-03

オブジェクト指向Fortranを使ってコードを書いていたら、使用メモリ量がどんどん増えていくバグに遭遇しました。deallocateしているはずなのにどんどん増えていきます。

問題のコード

コードはこんな感じです。

program main
    use test
    implicit none
    integer::N

    complex(8),allocatable::vec_data(:)

    N = 100000

    allocate(vec_data(N))

    vec_data = pmap(N,wrap)

    contains 

    function wrap(i)
        integer,intent(in)::i
        complex(8)::wrap
        type(type_test),allocatable::testdata
        allocate(testdata)
        testdata = type_test(N)
        wrap = 0d0
        deallocate(testdata)
    end function

end program 

ここで、type_testというクラスはmodule testで定義されており、

module test
    implicit none

    type type_test
        class(type_inner),allocatable::vec
    end type

    interface type_test
        module procedure::init_test
    end interface

    type type_inner
        complex(8),allocatable::x(:)
    end type

    interface type_inner
        module procedure::init_inner
    end interface

    contains 

    type(type_test) function init_test(N) result(testdata)
        integer::N
        allocate(testdata%vec)
        testdata%vec = init_inner(N) 
    end function

    type(type_inner) function init_inner(N) result(vec)
        integer::N,i
        allocate(vec%x(1:N))
        do i=1,N
            vec%x(i) = i
        end do
    end function

    function pmap(N,func) result(vec_data)
        interface 
            function func(i)
                integer,intent(in)::i
                complex(8)::func
            end function
        end interface
        integer,intent(in)::N
        integer::i
        complex(8)::v
        complex(8)::vec_data(N)

        do i=1,N
            vec_data(i) = func(i)
        end do

    end function

end module

です。フィールドにtype_innerというクラスを持ち、そのクラスの中で配列が確保されています。ですので、構造体のフィールドに構造体がありそのフィールドに配列、というものを用意しています。

結果

moduleを上に、mainを下に書いてgfortranでコンパイルして実行すると、なぜか使用メモリが増えていきます。deallocate(testdata)しているのに、メモリが増えていきます。

  • Mac OS 10.14および10.15
  • gfortran 9と10

で確認しました。

原因は不明です。

追記

@cure_honeyさんのコメントの通り、

    type(type_test) function init_test(N) result(testdata)
        integer::N
        type(type_inner) :: dummy

        dummy = init_inner(n)
        testdata%vec = dummy
    end function

とすることでメモリーリークが消えることが確認できました。

@implicit_none さんの提案のfinalizer処理の追加

    type type_test
        class(type_inner),allocatable::vec

        contains
        final :: vec_final ! finalizer
    end type

    subroutine vec_final(this)
        use, intrinsic :: iso_fortran_env
        implicit none
        type(type_test) :: this ! not "class"

        if (allocated(this%vec)) deallocate (this%vec)
    end subroutine vec_final

をやってみましたが、問題は解決できませんでした。deallocateを明示的に書いてもやってくれないのは、@cure_honeyさんのおっしゃるclassの具体形がわからないからでしょうか...

1
2
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2