Я написал довольно большую программу на 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:
, и это случай по умолчанию, который был вызван, возвращая текст Недействительный сигнал или ошибку
. К нему прилагается строка комментария, в которой странным образом говорится, что / * никогда не должно происходить, но компилятор не может сказать * /
... ?
Итак, я думаю, мой вопрос: почему это происходит и что происходит на самом деле? Я думал, что пока я могу выделить всю необходимую память, со мной все будет в порядке? Создает ли вызов подпрограммы копии аргументов или просто указатели на них? Если ответ - копии, то я вижу, в чем может быть проблема, и если да: есть ли идеи, как ее обойти?
Проблема, которую я пытаюсь решить, большая, но ни в коем случае не безумная. Стандартные решатели FE могут справиться с более серьезными проблемами, чем моя нынешняя. Я запускаю программу на Dell PowerEdge 1850, а операционная система - Microsoft Server 2008 R2 Enterprise. Согласно systeminfo
в приглашении cmd
, у меня 8 ГБ физической памяти и почти 16 ГБ виртуальной. Насколько я понимаю, общая сумма всех моих массивов и матриц не должна составлять более 100 МБ - около 5. 5M integer (4)
и 2,5M real (8)
(что, по моему мнению, должно быть всего около 44MB, но давайте будем честны и добавим еще 50MB на накладные расходы).
Я использую компилятор Intel Fortran, интегрированный с Microsoft Visual Studio 2008.
Добавление некоторого фактического исходного кода, чтобы немного прояснить
! 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
- все остальные как минимум на порядок меньше (если не больше). posc
is INTEGER (4)
и bmtrx
и aa
is 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)
...
И это не удается до последняя строка выше.