Запуск «GC.Collect» исправляет мой сбой, но я не понимаю, почему

StackOverflow https://stackoverflow.com/questions/995294

  •  13-09-2019
  •  | 
  •  

Вопрос

У меня есть этот фрагмент кода (из примера кода Nokia PC Connection 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 кажется, исключение исчезает.

Что здесь происходит и как правильно предотвратить исключение?

Это было полезно?

Решение

Ваша проблема в том, что вы передаете true методу Marshal.StructureToPtr, поэтому он пытается освободить два указателя строк (которые иногда недействительны).В этом случае вам нужно передать false, поскольку вы только что выделили эту память в куче.(т.е.там нечего освобождать).

Другие советы

Вы уверены, что 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

Используйте фиксированное ключевое слово, чтобы получить указатель на исходный файл. folderInfo.

Возможно, неуправляемые ресурсы чем-то не освобождаются.Проверьте, не реализовано ли что-нибудь из того, что вы используете. IDодноразовый и если да, то заверните его в using { } блокировать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top