Fortran Coder

标题: deallocate内存访问错误及DLL问题 [打印本页]

作者: andy8496    时间: 2015-4-16 02:43
标题: deallocate内存访问错误及DLL问题
本帖最后由 andy8496 于 2015-4-16 02:47 编辑

又遇到看不见摸不着的问题了!
运行到一个deallocate时,出现图中的错误了。被deallocate的real数组中的数值正常。
可能是什么原因?
这是一个比较大的程序,最近在做一些修改。可以肯定的是,相同位置以前老代码是没有遇到这个问题的。

另一个问题:
当A(main.exe)项目引用B项目(test.dll)时,只要设置A依赖B,不需要在A中添加B相关的文件,就能直接编译通过。但是debug运行时会提示找不着test.dll。
我目前是生成后,将B中的test.dll复制到A的debug文件夹中。还有别的办法吗?

1.jpg (19.82 KB, 下载次数: 421)

1.jpg

2.jpg (15.04 KB, 下载次数: 465)

2.jpg

作者: fcode    时间: 2015-4-16 08:51
有另外的问题,一般提倡另外发帖。(已帮你分隔)

问题1,不容易解决,通常这种错误都需要详细debug解决。有时候还可能需要反汇编解决。

问题2,一般我是设置 B 项目的输出路径,直接输出到 A 项目所在的位置。
作者: pasuka    时间: 2015-4-16 18:42
本帖最后由 pasuka 于 2015-4-16 18:43 编辑

在deallocate语句前面加个判断
if(allocated(**))deallocate(**)
还有可能是Fortran和C/C++混编的时候,数组越界,所以deallocate的时候出问题
作者: andy8496    时间: 2015-4-16 19:35
pasuka 发表于 2015-4-16 18:42
在deallocate语句前面加个判断
if(allocated(**))deallocate(**)
还有可能是Fortran和C/C++混编的时候,数 ...

应该不是这个原因。我使用deallocate的时候,加了最后的状态参数。还是谢谢了。
作者: andy8496    时间: 2015-4-16 19:43
我想我找到为什么出错的原因了。
我在a.exe中使用了b.dll的一个子程序。这个子程序的输出参数有一个是allocatable数组。
我在a.exe中声明了一个allocatable的数组,这个数组经b.dll中的子程序运算、输出,至此一切正常。
但是,用完这个allocatable的数组后,我在a.exe调用deallocate释放它时,就出现一楼所示的问题了。
怎么破?

附件中的工程是我做的例子,能再现这个问题。恳请大侠出手!在此谢过!

test.rar

6.07 KB, 下载次数: 7


作者: fcode    时间: 2015-4-16 19:46
良好的编程习惯:
谁打开,谁关闭。谁分配,谁释放。
作者: andy8496    时间: 2015-4-16 22:07
如果一定要这么做,有解决办法吗?
作者: fcode    时间: 2015-4-16 22:13
1. 在 test_main 里声明可分配数组
2. 调用 test_dll 里的一个函数,获得数组的大小 n
3. 在 test_main 里完成分配。allocate( x(n) )
4. 把 x 传递给 test_dll 里完成计算
5. 在 test_main 里 deallocate

由于可分配数组的内部实现,是编译器的问题(而语法是不干涉具体实现的)。而 DLL 又是windows的事情。
这几者间比较难以协调。

实际上,就算不用 DLL,单纯的 Fortran 工程,我也建议谁定义,谁分配,谁释放。

如果你确实确实要在主程序定义,DLL里分配,主程序释放。那我可能帮不了你。
作者: pasuka    时间: 2015-4-16 22:31
用gfortran编译成dll再调用没发现问题
只是在调用前加了个检查
  if(allocated(iv_int))deallocate(iv_int)
  call allocate_test(iv_int)
作者: andy8496    时间: 2015-4-16 23:52
真是太奇怪了!
1.上面的代码Debug的时候报错,但是Release的时候就运行正常!!!
2.正常情况下,allocate过的数组是不能再allocate的。但是,test_main.f90这样写居然没有报错:
program main
use test_dll
implicit none
  integer,allocatable :: iv_int(:)
  integer :: iStatus,i
  do i=1,10
    call allocate_test(iv_int,i)
    write(*,*) iv_int
  enddo
  stop
end program
这意思是说:dll中的allocate不关主程序的事?
3.但是这么写又有问题了:
program main
use test_dll
implicit none
  integer,allocatable :: iv_int(:)
  integer :: iStatus,i
  do i=1,10
    call allocate_test(iv_int,i)
    write(*,*) iv_int
  enddo
  allocate(iv_int(8)) ! 到这里报错了,说这是分配过的数组
  stop
end program

4.难道确实是分配了,只是只有dll知道分配到哪儿了,主程序不知道?于是又这么改了下:
Dll加上这么一个函数:
subroutine deallocate_test(iv)
!DEC$ ATTRIBUTES STDCALL,REFERENCE,DLLEXPORT,ALIAS:"deallocate_test"::deallocate_test
implicit none
  integer,allocatable :: iv(:)
  integer :: iStatus
  deallocate(iv,stat=iStatus)
return
end subroutine

主程序这么写:
program main
use test_dll
implicit none
  integer,allocatable :: iv_int(:)
  integer :: iStatus,i
  do i=1,10
    call allocate_test(iv_int,i)
    write(*,*) iv_int
  enddo
  call deallocate_test(iv_int)
  allocate(iv_int(8))
  deallocate(iv_int,stat=iStatus)
  stop
end program

这么就一切正常了。
5.那回到1,Release的时候主程序又是如何知道dll分配的地址,成功的deallocate掉的呢?


哎,真是一团浆糊啊!有没有完美的解决之道啊?


作者: fcode    时间: 2015-4-17 08:25
正如之前我说过的那样,这是具体编译器实现的问题。你要想深究为什么,恐怕只能反汇编分析。

正如 pasuka 所言,gfortran 是 OK的,所以不同编译器实现不一样。

同一个编译器,Debug 和 Release 的具体实现也不一样。我不认为研究这个问题有什么意义。

还是那句话:“即便不使用DLL,合理的规范的做法是:谁分配,谁释放”,尤其做大一些的工程时候,这不止是避免程序上出错,也可避免逻辑上出错。而后者非常重要。
作者: pasuka    时间: 2015-4-17 08:55
fcode 发表于 2015-4-17 08:25
正如之前我说过的那样,这是具体编译器实现的问题。你要想深究为什么,恐怕只能反汇编分析。

正如 pasuka  ...

可分配数组传入子程序后在进行内存分配好像是F08新特性,有可能lz的IVF版本低,所以不支持?!
此外就是Debug和Release的状态下,IVF编译参数不同导致出现问题
作者: fcode    时间: 2015-4-17 09:52
pasuka 发表于 2015-4-17 08:55
可分配数组传入子程序后在进行内存分配好像是F08新特性,有可能lz的IVF版本低,所以不支持?!
此外就是D ...

这是 F2003 特征,IVF是予以支持的。很早就支持了。这个不存在问题。

但是这个特征需要 interface,如果不再同一个module里,可能要单独书写 interface
作者: andy8496    时间: 2015-4-18 11:30
fcode 发表于 2015-4-17 08:25
正如之前我说过的那样,这是具体编译器实现的问题。你要想深究为什么,恐怕只能反汇编分析。

正如 pasuka  ...

只是因为以前的开发习惯不好,用了很多这样的方式:Dll中分配,main.exe中释放,main.exe中open, dll中write,现在都出问题了。之前没用dll,所以好好的。看来只能改代码了。

非常感谢二位的耐心帮助!

作者: pasuka    时间: 2015-4-19 21:36
fcode 发表于 2015-4-17 09:52
这是 F2003 特征,IVF是予以支持的。很早就支持了。这个不存在问题。

但是这个特征需要 interface,如果 ...

查了Gfortran的更新记录,TR 15581从4.2版本就开始支持
stackoverflow上面的解答可能更全面些:
How to pass allocatable arrays to subroutines in Fortran - Stack Overflow
http://stackoverflow.com/questio ... routines-in-fortran

作者: andy8496    时间: 2015-4-20 18:58
我用的VS2010+IVF2011。可变长度数组做参数这个好像没有问题。只是用完后释放有问题。同时还有open、write的问题。
已经按照fcode的建议改了代码了。

谢谢大家了!




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