从托管DLL调用时非托管DLL中的堆栈溢出异常

时间:2010-03-24 02:33:14

标签: c# unmanaged fortran managed

我的问题类似于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,这似乎不是很多元素,不是吗?

2 个答案:

答案 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谈论它。