C# GC 可以移动静态 class 方法吗?
Can C# GC move static class method?
我知道,GC 可以移动对象,所以如果您想暂时避免这种情况,可以使用
GCHandle.Alloc(..., GCHandleType.Pinned)
我想将一个C#函数传递给C++ DLL,它会被调用多次。
我看到 关于如何将 C# 函数传递给 C++ DLL 的回答,我的方法是:
C++:
#include <string>
typedef void(*MyFunction)(const char*);
void foo(MyFunction func) {
for (int i = 0; i < 1000; i++) {
std::string s = std::to_string(i);
func(s.c_str());
}
}
C#:
class Program {
delegate void MyFunction([MarshalAs(UnmanagedType.LPStr)] string s);
[DllImport(..., CallingConvention = CallingConvention.Cdecl)]
static extern foo(MyFunction function);
static void Baz(string s) {
Console.WriteLine(s);
}
private static MyFunction delegateInstance;
static void Main(string[] args) {
delegateInstance = Baz;
foo(delegateInstance);
}
}
如果为 x64 构建,此程序运行良好,但如果为 x86 构建,则静默死亡。我认为 GC 在某个时候移动了我的 Baz
函数,而 C++ DLL 正在尝试调用它。
如果是,我该如何避免?
编辑
看起来委托函数必须用 UnmanagedFunctionPointer
声明才能看起来像
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void MyFunction([MarshalAs(UnmanagedType.LPStr)] string s);
现在它工作正常,但有谁知道,为什么有必要并且在 x64 上工作?
x64 上只有一种调用约定(不是 cdecl)。您的 CallingConvention.Cdecl
仅适用于 x86(存在多个有效调用约定)。因此,在 x64 上指定的“错误”调用约定下一切正常也就不足为奇了,因为只有一种可能的调用约定,因此您的 CallingConvention
被忽略了。
但是切换到 x86 并突然指定错误的调用约定很重要。
另请注意,调用约定错误会导致您的应用立即崩溃。 GC 问题往往会在几秒钟后出现——事情会工作一段时间,然后停止工作。应该很容易区分与 GC 相关的问题(工作一段时间,然后停止)和其他类型的 p/invoke 问题(导致立即崩溃)
我知道,GC 可以移动对象,所以如果您想暂时避免这种情况,可以使用
GCHandle.Alloc(..., GCHandleType.Pinned)
我想将一个C#函数传递给C++ DLL,它会被调用多次。
我看到
C++:
#include <string>
typedef void(*MyFunction)(const char*);
void foo(MyFunction func) {
for (int i = 0; i < 1000; i++) {
std::string s = std::to_string(i);
func(s.c_str());
}
}
C#:
class Program {
delegate void MyFunction([MarshalAs(UnmanagedType.LPStr)] string s);
[DllImport(..., CallingConvention = CallingConvention.Cdecl)]
static extern foo(MyFunction function);
static void Baz(string s) {
Console.WriteLine(s);
}
private static MyFunction delegateInstance;
static void Main(string[] args) {
delegateInstance = Baz;
foo(delegateInstance);
}
}
如果为 x64 构建,此程序运行良好,但如果为 x86 构建,则静默死亡。我认为 GC 在某个时候移动了我的 Baz
函数,而 C++ DLL 正在尝试调用它。
如果是,我该如何避免?
编辑
看起来委托函数必须用 UnmanagedFunctionPointer
声明才能看起来像
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void MyFunction([MarshalAs(UnmanagedType.LPStr)] string s);
现在它工作正常,但有谁知道,为什么有必要并且在 x64 上工作?
x64 上只有一种调用约定(不是 cdecl)。您的 CallingConvention.Cdecl
仅适用于 x86(存在多个有效调用约定)。因此,在 x64 上指定的“错误”调用约定下一切正常也就不足为奇了,因为只有一种可能的调用约定,因此您的 CallingConvention
被忽略了。
但是切换到 x86 并突然指定错误的调用约定很重要。
另请注意,调用约定错误会导致您的应用立即崩溃。 GC 问题往往会在几秒钟后出现——事情会工作一段时间,然后停止工作。应该很容易区分与 GC 相关的问题(工作一段时间,然后停止)和其他类型的 p/invoke 问题(导致立即崩溃)