我在另一个子程序(FindVee)中调用(外部)子程序Objee:
subroutine FindVee(EVone,Vw0,Ve,Fye)
use nag_library, only: nag_wp
use My_interface_blocks, only: Objee
...
implicit none
real(kind=nag_wp) :: apmax, Val
...
call Objee(apmax,Val)
write(*,*) 'After Objee', apmax, Val
...
end subroutine FindVee
子程序Objee是:
subroutine Objee(ap,V)
use nag_library, only: nag_wp
...
implicit none
real(kind=nag_wp), intent(in) :: ap
real(kind=nag_wp), intent(out):: V
...
V = U(x,sigma) + beta*piy*yhat1(Nav*(Nav+1)/2) + &
& beta*eta*(1.0e0-piy)*yhat2(Nav*(Nav+1)/2)
V = - V
write(*,*) 'Exit Objee', ap, V
end subroutine Objee
运行这样的代码,在屏幕上产生以下打印:
退出Objee 0.0000000000000000 9997.5723796583643
程序接收信号SIGBUS:访问a的未定义部分 记忆对象。
此错误的Backtrace:
中
#0 0x7FAA7ADFF7D7
#1 0x7FAA7ADFFDDE
#2 0x7FAA7A533FEF
#3 0x423B29在findvee_程序接收信号SIGSEGV:分段故障 - 内存无效 参考
此错误的Backtrace:
#0 0x7FAA7ADFF7D7
#1 0x7FAA7ADFFDDE
#2 0x7FAA7A533FEF
#3 0x7FAA7A0B9BA0
#4 0x7FAA7A0BAEFD
#5 0x7FAA7ADFF7D7
#6 0x7FAA7ADFFDDE
#7 0x7FAA7A533FEF
#8 0x423B29在findvee_分段故障(核心转储)
我使用gfortran 4.8.1,使用以下选项:-fopenmp -fcheck = all -fcheck = bounds -Wall -Wimplicit-interface -Wimplicit-procedure。编译器没有显示任何警告。
经过一周的尝试各种各样的事情并扫描一半的互联网以找出发生的事情的线索后,我想我会在Objee打印出V形的形状,然后看看Fortran给了我什么 - 不知怎的,事实证明它解决了这个问题:
subroutine Objee(ap,V)
...
write(*,*) 'Exit Objee', ap, V, shape(V)
end subroutine Objee
在屏幕上显示以下内容:
Exit Objee 0.0000000000000000 9997.5723796583643
After Objee 0.0000000000000000 9997.5723796583643
魔术!一切正常,似乎一切都是正确的。有人可以向我解释一下这里发生了什么吗?而且,我每次打电话给奥布杰(这将是成千上万的......)时,如何在屏幕上不打印形状(V)的情况下解决所发生的事情。
运行valgrind ./programa --leak-check=full
后,我获得以下输出:
==2784== Invalid write of size 8
==2784== at 0x423B3F: findvee_ (FindVee.f95:66)
==2784== by 0x8: ???
==2784== Address 0x7ffffffffffffda8 is not stack'd, malloc'd or (recently) free'd
==2784==
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x4E4D7D7
#1 0x4E4DDDE
#2 0x56A3FEF
#3 0x423B3F in findvee_ at FindVee.f95:66
==2784== Invalid read of size 8
==2784== at 0x5C7FBA0: ??? (in /lib/x86_64-linux-gnu/libgcc_s.so.1)
==2784== by 0x5C80EFD: _Unwind_Backtrace (in /lib/x86_64-linux-gnu/libgcc_s.so.1)
==2784== by 0x4E4D7D7: _gfortran_backtrace (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==2784== by 0x4E4DDDE: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==2784== by 0x56A3FEF: ??? (in /lib/x86_64-linux-gnu/libc-2.17.so)
==2784== by 0x423B3E: findvee_ (FindVee.f95:64)
==2784== by 0x8: ???
==2784== Address 0x8000000000000008 is not stack'd, malloc'd or (recently) free'd
==2784==
==2784==
==2784== Process terminating with default action of signal 11 (SIGSEGV)
==2784== General Protection Fault
==2784== at 0x5C7FBA0: ??? (in /lib/x86_64-linux-gnu/libgcc_s.so.1)
==2784== by 0x5C80EFD: _Unwind_Backtrace (in /lib/x86_64-linux-gnu/libgcc_s.so.1)
==2784== by 0x4E4D7D7: _gfortran_backtrace (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==2784== by 0x4E4DDDE: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==2784== by 0x56A3FEF: ??? (in /lib/x86_64-linux-gnu/libc-2.17.so)
==2784== by 0x423B3E: findvee_ (FindVee.f95:64)
==2784== by 0x8: ???
==2784==
==2784== HEAP SUMMARY:
==2784== in use at exit: 3,859 bytes in 20 blocks
==2784== total heap usage: 157 allocs, 137 frees, 300,126 bytes allocated
==2784==
==2784== LEAK SUMMARY:
==2784== definitely lost: 58 bytes in 1 blocks
==2784== indirectly lost: 0 bytes in 0 blocks
==2784== possibly lost: 0 bytes in 0 blocks
==2784== still reachable: 3,801 bytes in 19 blocks
==2784== suppressed: 0 bytes in 0 blocks
==2784== Rerun with --leak-check=full to see details of leaked memory
==2784==
==2784== For counts of detected and suppressed errors, rerun with: -v
==2784== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)
Segmentation fault (core dumped)
第64和66行(输出点为):
64 call Objee(apmax,Val)
66 write(*,*) 'After Objee', apmax, Val
作为一个没有经验的用户,除了指向我已经怀疑导致崩溃的代码部分之外,我并不是真的理解这对我有什么帮助。我在这里缺少什么?
答案 0 :(得分:1)
Fortran中的内存错误有两个常见原因。 1)非法下标访问。 2)过程调用中的实际参数与子例程的伪参数不匹配。现代编译器和Fortran> = 90让程序员帮助找到这些问题。正如Peter所建议的那样,您是否正在使用编译器的完整警告和错误选项,尤其是。运行时下标检查? (您使用的是什么编译器?)如果您将过程放在一个模块中,use
该模块Fortran将检查调用参数和子例程之间的一致性。当一个程序在一个模块中时,它的界面是已知的"到其他程序或使用该模块的主程序,启用此检查。使用这两种方法会发现许多导致内存问题的错误。
添加"随机"诸如输出之类的语句可以阻止内存错误,非法内存访问可能会对可以容忍的新代码造成损害,而在它造成致命损坏之前,例如过度写入具有数据值的地址,会产生非法地址。这些错误很难诊断,因为致命错误似乎与代码错误无关。第一段中描述的工具可以提供很大的帮助。