我的问题类似于this one here,但有一些区别。
我有一个fortran dll作为后端,而一个C#exe作为前端。我使用PInvoke在它们之间传递数据。
C#和fortran代码之间有22个参数。其中一些是整数,双精度,指针(C#指针),数组和诸如此类的东西。所以它是各种类型的混合。
问题是对于小型数组,代码工作正常,但是,对于大型数组(~10k元素大小),在我的代码进入托管代码后立即抛出stackoverflowexception。
编辑:我成功缩小了一切。这是fortran代码:
subroutine chartest(maxncv,ldv)
!DEC$ ATTRIBUTES DLLEXPORT::chartest
!DEC$ ATTRIBUTES ALIAS:'chartest'::chartest
!DEC$ ATTRIBUTES VALUE :: maxncv,ldv
&
integer, intent(in) :: maxncv, ldv
Double precision
& v(ldv,maxncv),d(maxncv,2)
print *, 'hello'
end
这是我的C#声明:
public static extern void chartest(
[MarshalAs(UnmanagedType.I4)] int maxncv,
[MarshalAs(UnmanagedType.I4)] int ldv
);
如果我调用chartest(546, 547)
,我会得到一个stackoverflowexception。
546*547=298662
,这似乎不是很多元素,不是吗?
答案 0 :(得分:2)
你没有提到你正在编译Fortran的内容,但很明显,当你分配数组时,那个内存正在堆栈上分配,这是一件非常糟糕的事情。 .NET假设最终会出现在堆栈上的大部分东西都会很小,比如对象引用或整数,所以它默认为1 MB堆栈大小。
你的298662双打(每个可能是8或10个字节)的例子在2-3 MB的范围内,超过了1MB的堆栈大小。
我找到了对英特尔Fortran编译器选项的引用:
http://software.intel.com/en-us/forums/showthread.php?t=53881
它表示你可以通过将/ heap-arrays传递给编译器来避免在堆栈上分配数组。我希望其他Fortran编译器会有类似的东西,或者默认使用堆数组。
答案 1 :(得分:1)
我对此感到困惑,但是一些谷歌搜索似乎表明不可能“轻松”改变托管应用程序中的堆栈大小。可能是我缺乏知识使我无法理解为什么这不重要。但是,如果从主线程调用它,您似乎可以使用名为editbin.exe
的实用程序来增加堆栈大小。如果在您创建的单独线程上进行调用,则可以指定堆栈大小。 This blog post谈论它。