运行“GC.Collect” 修复了我的崩溃,但我不明白为什么
我有这段代码(来自诺基亚 PC 连接 3.2 示例代码,C# 语言):
DAContentAccessDefinitions.CA_FOLDER_INFO folderInfo =
new DAContentAccessDefinitions.CA_FOLDER_INFO();
folderInfo.iSize = Marshal.SizeOf(folderInfo); //(32)
IntPtr bufItem = Marshal.AllocHGlobal(folderInfo.iSize);
//I often get a AccessViolationException on the following line
Marshal.StructureToPtr(folderInfo, bufItem, true);
如果我在开始时运行 GC.Collect()
,那么我不会得到 AccessViolationException
。 但除非必要,否则我不想放慢这个功能。 我尝试将 GC.Keepalive 放在不同的地方,但没有成功。
CA_FOLDER_INFO
定义为:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct CA_FOLDER_INFO
{
public int iSize;
public int iFolderId;
public int iOptions;
public string pstrName;
public string pstrPath;
public int iSubFolderCount;
public IntPtr pSubFolders;
public IntPtr pParent;
}
在本例中,我不需要任何一个字符串,并且将它们的定义更改为 IntPtr
似乎可以使异常消失。
这是怎么回事,防止异常的正确方法是什么?
I have this piece of code (from the Nokia PC connectivity 3.2 example code, in C#):
DAContentAccessDefinitions.CA_FOLDER_INFO folderInfo =
new DAContentAccessDefinitions.CA_FOLDER_INFO();
folderInfo.iSize = Marshal.SizeOf(folderInfo); //(32)
IntPtr bufItem = Marshal.AllocHGlobal(folderInfo.iSize);
//I often get a AccessViolationException on the following line
Marshal.StructureToPtr(folderInfo, bufItem, true);
If I run GC.Collect()
at the start of this, then I don't get an AccessViolationException
. But I don't want to slow down this function unless necessary. I've tried putting GC.Keepalive
in various places, but without success.
CA_FOLDER_INFO
is defined as:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct CA_FOLDER_INFO
{
public int iSize;
public int iFolderId;
public int iOptions;
public string pstrName;
public string pstrPath;
public int iSubFolderCount;
public IntPtr pSubFolders;
public IntPtr pParent;
}
I don't, in this instance, require either of the strings, and changing their definitions to IntPtr
seems to make the exception go away.
What is going on here, and what is the correct way to prevent the exception?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您的问题是您将 true 传递给 Marshal.StructureToPtr,因此它尝试释放两个字符串指针(有时无效)。 在这种情况下,您需要传递 false,因为您刚刚在堆上分配了该内存。 (即那里没有什么可以释放的)。
Your problem is that you're passing true to Marshal.StructureToPtr so it attempts to free the two string pointers (which are sometimes invalid). You need to pass false in this instance since you just allocated that memory on the heap. (i.e. there's nothing to free there).
您确定 Marshal.Sizeof(bufItem) 和 Marshal.Sizeof(folderInfo) 相同吗?
而且,也许您没有初始化字符串? 既然你说当它们是 IntPtr (默认为 IntPtr.Zero)时你不会收到错误,所以在尝试封送缓冲区项之前,我会尝试将它们都设置为空字符串。
[编辑]
也许您应该尝试固定缓冲区句柄,并将其编组到结构,而不是反之亦然。 像这样的事情:
Are you sure Marshal.Sizeof(bufItem) and Marshal.Sizeof(folderInfo) are the same?
And, maybe the fact that you aren't initializing the strings? Since you say you don't get the error when they are IntPtr (which defaults to IntPtr.Zero), I'd try setting them both to empty strings before you try marshaling the buffer item.
[Edit]
Maybe you should try pinning the buffer handle, and marshaling that to the structure, rather than vis versa. Something like this:
使用fixed关键字获取指向原始
folderInfo
的指针。Use the fixed keyword to get a pointer to your original
folderInfo
.可能是非托管资源没有被某些东西释放。 检查您使用的任何内容是否实现了 IDisposable 以及如果是这样,请将其包装在
using { }
块中。It could be that unmanaged resources aren't being released by something. Check to see if anything you're using implements IDisposable and if so, wrap it in a
using { }
block.