运行'GC.Collect'修复了我的崩溃,但我不明白为什么

时间:2009-06-15 09:59:36

标签: c# unmanaged nokia

我有这段代码(来自诺基亚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似乎会使异常消失。

这里发生了什么,以及防止异常的正确方法是什么?

4 个答案:

答案 0 :(得分:5)

你的问题是你将true传递给Marshal.StructureToPtr,所以它试图释放两个字符串指针(有时无效)。您需要在此实例中传递false,因为您刚刚在堆上分配了该内存。 (即那里没有任何东西可以释放)。

答案 1 :(得分:0)

使用fixed关键字获取指向原始folderInfo的指针。

答案 2 :(得分:0)

可能是某些东西没有释放非托管资源。检查您使用的是否有任何实现IDisposable,如果是,请将其包装在using { }块中。

答案 3 :(得分:0)

你确定Marshal.Sizeof(bufItem)和Marshal.Sizeof(folderInfo)是一样的吗?

而且,也许您没有初始化字符串这一事实?因为你说你在IntPtr(默认为IntPtr.Zero)时没有得到错误,所以在尝试编组缓冲项之前,我会尝试将它们都设置为空字符串。

<强> [编辑]

也许您应该尝试固定缓冲区句柄,并将其整理到结构中,而不是相反。像这样:

DAContentAccessDefinitions.CA_FOLDER_INFO folderInfo;

GCHandle pinnedHandle = GCHandle.Alloc(buffItem, GCHandleType.Pinned);
folderInfo = (DAContentAccessDefinitions.CA_FOLDER_INFO)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(DAContentAccessDefinitions.CA_FOLDER_INFO));
pin.Free();

//folderInfo should contain the data from buffItem