私は Fortran 90 でかなり大きなプログラムを書きました。それはかなり長い間美しく動作していましたが、今日はそれを一段階上げて問題のサイズを大きくしようとしました (それが研究用の非標準 FE ソルバーである場合、誰にも役立ちます...) 今、「スタックオーバーフロー」エラーメッセージが表示され、プログラムは当然、作業に役立つものを何も提供せずに終了します。
プログラムは、関連するすべての配列と行列の設定から開始し、その後、これに関する数行の統計をログ ファイルに出力します。私の新しいより大きな問題でも、これはうまく機能しますが(少し遅いですが)、「数の計算」が進むにつれて失敗します。
私を混乱させるのは、その時点ですべてがすでに割り当てられていることです(そして、エラーなしで機能しました)。スタックが何であるかは完全にはわかりません (ウィキペディアとここのいくつかのトレッドは、コンピューターの「舞台裏」の仕組みについて非常に基本的な知識しか持っていないため、あまり役に立ちませんでした)。
たとえば、次のように初期化されたいくつかの配列があるとします。
INTEGER,DIMENSION(64) :: IA
REAL(8),DIMENSION(:,:),ALLOCATABLE :: AA, BB
いくつかの初期化ルーチン(つまり、ファイルからの入力の読み取りなど)が次のように割り当てられた後、次のように割り当てられます(固定サイズのIAのサブルーチンに簡単に渡すために、いくつかのサイズ整数を保存します):
ALLOCATE( AA(N1,N2) , BB(N1,N2) )
IA(1) = N1
IA(2) = N2
これは基本的に最初の部分で発生することであり、これまでのところ問題ありません。しかし、次にサブルーチンを呼び出すと
CALL ROUTINE_ONE(AA,BB,IA)
そして、ルーチンは次のようになります (派手なものはありません):
SUBROUTINE ROUTINE_ONE(AA,BB,IA)
IMPLICIT NONE
INTEGER,DIMENSION(64) :: IA
REAL(8),DIMENSION(IA(1),IA(2)) :: AA, BB
...
do lots of other stuff
...
END SUBROUTINE ROUTINE_ONE
今、私はエラーが発生します!画面への出力には次のように表示されます。
forrtl: severe (170): Program Exception - stack overflow
ただし、デバッガーでプログラムを実行すると、419 行目で、というファイルwinsig.c
(私のファイルではなく、おそらくコンパイラーの一部?) で中断します。呼び出されたルーチンの一部のようであり、sigreterror:
呼び出されたのはデフォルトのケースであり、テキストを返しますInvalid signal or error
。これに奇妙なことにコメント行が添付されています/* should never happen, but compiler can't tell */
...?
だから私の質問は、なぜこれが起こるのか、そして実際に何が起こっているのかということだと思います. 関連するすべてのメモリを割り当てることができる限り、私は大丈夫だと思いましたか? サブルーチンの呼び出しは、引数のコピーを作成しますか、それとも単にそれらへのポインタを作成しますか? 答えがコピーである場合、問題がどこにあるのかがわかります。もしそうなら、それを回避する方法についてのアイデアはありますか?
私が解決しようとしている問題は大きいですが、決して正気ではありません。標準的な FE ソルバーは、現在の問題よりも大きな問題を処理できます。Dell PowerEdge 1850 でプログラムを実行しており、OS は Microsoft Server 2008 R2 Enterprise です。プロンプトによるとsysteminfo
、cmd
8 GB の物理メモリとほぼ 16 GB の仮想メモリがあります。私が理解している限り、すべての配列とマトリックスの合計は、おそらく 100MB を超えてはならない - 約 5.5Minteger(4)
と 2.5M real(8)
(私によれば、これは約 44MB しかないはずですが、公平を期して、オーバーヘッドのためにさらに 50MB を追加しましょう) )。
Microsoft Visual Studio 2008 に統合された Intel Fortran コンパイラを使用しています。
少し明確にするために実際のソースコードを追加する
! Update continuum state
CALL UpdateContinuumState(iTask,iArray,posc,dof,dof_k,nodedof,elm,&
bmtrx,detjac,w,mtrlprops,demtrx,dt,stress,strain,effstrain,&
effstress,aa,fi,errmsg)
ルーチンへの実際の呼び出しです。大きな配列はposc
、bmtrx
およびaa
- 他のすべてのものは、少なくとも 1 桁小さい (それ以上ではないにしても) です。posc
でINTEGER(4)
ありbmtrx
、でaa
あるREAL(8)
SUBROUTINE UpdateContinuumState(iTask,iArray,posc,dof,dof_k,nodedof,elm,bmtrx,&
detjac,w,mtrlprops,demtrx,dt,stress,strain,effstrain,&
effstress,aa,fi,errmsg)
IMPLICIT NONE
!I/O
INTEGER(4) :: iTask, errmsg
INTEGER(4) :: iArray(64)
INTEGER(4),DIMENSION(iArray(15),iArray(15),iArray(5)) :: posc
INTEGER(4),DIMENSION(iArray(22),iArray(21)+1) :: nodedof
INTEGER(4),DIMENSION(iArray(29),iArray(3)+2) :: elm
REAL(8),DIMENSION(iArray(14)) :: dof, dof_k
REAL(8),DIMENSION(iArray(12)*iArray(17),iArray(15)*iArray(5)) :: bmtrx
REAL(8),DIMENSION(iArray(5)*iArray(17)) :: detjac
REAL(8),DIMENSION(iArray(17)) :: w
REAL(8),DIMENSION(iArray(23),iArray(19)) :: mtrlprops
REAL(8),DIMENSION(iArray(8),iArray(8),iArray(23)) :: demtrx
REAL(8) :: dt
REAL(8),DIMENSION(2,iArray(12)*iArray(17)*iArray(5)) :: stress
REAL(8),DIMENSION(iArray(12)*iArray(17)*iArray(5)) :: strain
REAL(8),DIMENSION(2,iArray(17)*iArray(5)) :: effstrain, effstress
REAL(8),DIMENSION(iArray(25)) :: aa
REAL(8),DIMENSION(iArray(14)) :: fi
!Locals
INTEGER(4) :: i, e, mtrl, i1, i2, j1, j2, k1, k2, dim, planetype, elmnodes, &
Nec, elmpnodes, Ndisp, Nstr, Ncomp, Ngpt, Ndofelm
INTEGER(4),DIMENSION(iArray(15)) :: doflist
REAL(8),DIMENSION(iArray(12)*iArray(17),iArray(15)) :: belm
REAL(8),DIMENSION(iArray(17)) :: jelm
REAL(8),DIMENSION(iArray(12)*iArray(17)*iArray(5)) :: dstrain
REAL(8),DIMENSION(iArray(12)*iArray(17)) :: s
REAL(8),DIMENSION(iArray(17)) :: ep, es, dep
REAL(8),DIMENSION(iArray(15),iArray(15)) :: kelm
REAL(8),DIMENSION(iArray(15)) :: felm
dim = iArray(1)
...
そして、上記の最後の行の前で失敗します。