Fortran Coder

标题: 新手求助 有关allocate与deallocate之后数组值为undefined [打印本页]

作者: noobnobb    时间: 2023-4-12 16:36
标题: 新手求助 有关allocate与deallocate之后数组值为undefined
使用oneAPI2021里的INF,visual studio2019 编写Fortran程序
代码大致内容如下:在循环外定义十几个可分配的数组,循环中,对一矩阵的每一列进行操作,根据每列都会生成许多不同大小的数组,因此使用动态数组,使用这些数组进行运算,在循环结尾处都会deallocate。
问题是:在不打断点的调试时,会触发异常如图1,同样的数据同样的代码,运气好能正确地多跑几轮循环(是想要的结果),有时就第一轮直接异常。详细查看后会显示是如图2,调试过近百次,所有的错误最终都是堆已损坏,将近99%的错误发生地点都是allocate和deallocate,debug查看异常点要分配的数组会发现其都是已经被分配了大小,但值都是undefined address如图3;剩下那百分之一的错误是一个动态数组里的值莫名其妙被修改了。

我太菜了,查了好久也没查到所以然,关于undefined address 的描述都很少,我初步猜测是分配和释放时出现了问题导致了错误值。
恳请大佬们答疑解惑,万般感激。

图3 undefined address.png (8.3 KB, 下载次数: 234)

图3 undefined address

图3 undefined address

图2 堆已损坏.png (28.93 KB, 下载次数: 250)

图2 堆已损坏

图2 堆已损坏

作者: Transpose    时间: 2023-4-12 20:07
可能是传入的C有问题,可以输出size(c)看看是多少
作者: noobnobb    时间: 2023-4-12 20:18
本帖最后由 noobnobb 于 2023-4-12 20:23 编辑
Transpose 发表于 2023-4-12 20:07
可能是传入的C有问题,可以输出size(c)看看是多少

谢谢你的回复哦,不过这个应该不是C的问题,C的数据如下图。  我在问题描述中只列举了报错中的一个例子,其实是每个allocate和每个deallocate方法都有可能报错,这几条来回报错,不一定是哪个。  


再补充一下,程序是对180*180的矩阵操作,算法需要对每列单独操作,因此循环180列,每次循环都屏幕输出当前循环的结果。运行结果有时第二、三次循环就报错,有时却十几次,最多只能跑到二十多次。


1.png (16.28 KB, 下载次数: 247)

C数组

C数组

作者: Transpose    时间: 2023-4-12 20:22
没法判断,可能需要源代码
作者: noobnobb    时间: 2023-4-12 20:28
Transpose 发表于 2023-4-12 20:22
没法判断,可能需要源代码

谢谢大佬,不过我写得shit一样,真不想污染大家的眼睛,小小简单算法还三四百行,惭愧啊,我自己再找找,刚才还发现了一些数组的数值不知怎么被改成了极其离谱的数据,想着再从这方面切入去找一找。或者是因为动态数组的隐藏自动分配?   不过既然有的循环能出现正确的结果那说明代码应该没问题,应该是内存或者优化不够的问题吧。
作者: Transpose    时间: 2023-4-12 20:47
你可以多加一些print看看
另外,可以再用gfortran编译试试 ,两种编译器同时使用,结合起来可能会有效果, 编译的时候加上-fcheck=all

作者: noobnobb    时间: 2023-4-13 09:42
Transpose 发表于 2023-4-12 20:47
你可以多加一些print看看
另外,可以再用gfortran编译试试 ,两种编译器同时使用,结合起来可能会有效果, 编译 ...

好的,感谢大佬提供思路
作者: necrohan    时间: 2023-4-14 12:23
ALLOCATE和DEALLOCATE增加状态判断试试,比如ALLOCATE(S(100), STAT=sv]) ,然后比较sv是否为0判断是否正常分配数组。
作者: noobnobb    时间: 2023-4-14 17:07
本帖最后由 noobnobb 于 2023-4-14 17:50 编辑
necrohan 发表于 2023-4-14 12:23
ALLOCATE和DEALLOCATE增加状态判断试试,比如ALLOCATE(S(100), STAT=sv]) ,然后比较sv是否为0判断是否正常 ...

感谢大佬的回复,不过实际上发生异常时这条分配/释放语句并没有完全执行,应该是在执行过程中中断了,但有意思的是,在加与不加stat = status这个参数的对比过程中,我发现其在debug界面表现出的结果是不同的,下面附了两张图,分别是在allocate中加入与不加stat参数的运行实例。这也确实印证了您的想法,即这条allocate语句应该是没有正确分配到空间或是中断运行没有正常退出。之后又做了一个小测试,在allocate前将status赋为其他值,发现只要该allocate语句触发异常就不会改变status的值,试过0,-1,2,是在debug的变量页面查看的status值,应该可以判断是异常退出了allocate语句,附上status=2和status=0的图在最下。
再补充一下,上述的问题,目前运行了几十次全部出现在动态一维数组中,轮流出现。


我目前是在往数组越界方面着想,因为我在尝试过其他一些小矩阵(3*3)的例子之后发现仍然有这个allocate问题,只是其成功率会很高,只有很少的几率会出现问题,大概是8:2的比例,试过4个3*3的小矩阵的例子,结果也是想要的结果,因此我认为不可能是内存不够的问题。

请大佬指示!!!

加入status调试.png (76.93 KB, 下载次数: 241)

加入status调试

加入status调试

未加status调试.png (66.33 KB, 下载次数: 247)

未加status调试

未加status调试

status提前设为2.png (37.61 KB, 下载次数: 251)

status提前设为2

status提前设为2

status提前设为0.png (48.14 KB, 下载次数: 244)

status提前设为0

status提前设为0

作者: noobnobb    时间: 2023-4-14 17:30
本帖最后由 noobnobb 于 2023-4-14 17:31 编辑

接上我在一楼所说的,其中有1%的错误是有一个数组值被修改了,变成了很离谱的数,通过不断的输出确定范围,最终是抓到了元凶"call sgemm( )"。是MKL库中的计算矩阵-矩阵乘法的方法,应该是我用它来计算矩阵-一维数组(向量)才导致的问题,可能也是这里导致的数组越界,还是不够严谨
下图是寻找过程

数组值被篡改.png (86.8 KB, 下载次数: 253)

数组值被修改

数组值被修改

作者: noobnobb    时间: 2023-4-16 12:53
结束了结束了,找到了 就是数组越界,问题就出在10#说的,解决办法两种:1是换成用来计算矩阵-向量乘法的sgemv(),2是直接将这个向量定义为一行或一列的二维数组,我目前是嫌麻烦直接用了法2,成功且正确计算了。
但这也产生一个新的问题:对于能存储同样大小数据的数组,一维二维数组的区别在哪里,内存上又是怎么体现的? 就Fortran而言,定义 A(2,1) 和 定义A(2) 的区别是啥,只是shape()的区别吗?  C语言等其他默认数组下标从0开始的数组是不是就没有这个问题因为它们不能定义成A(1,0)?
求大佬解答




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2