El funcionamiento de un 'GC.Collect' corrige mi accidente, pero no entiendo por qué
Pregunta
Tengo este pedazo de código (de la conectividad de Nokia PC Código 3.2 ejemplo, en 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);
Si me quedo GC.Collect()
al comienzo de esta, entonces no consigo un AccessViolationException
. Pero no quiero para frenar esta función si no es necesario. He intentado poner GC.Keepalive
en varios lugares, pero sin éxito.
CA_FOLDER_INFO
se define como:
[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;
}
No, en este caso, obligan a las cuerdas, y el cambio de sus definiciones a IntPtr
parece hacer la excepción desaparece.
Lo que está pasando aquí, y lo que es la forma correcta para evitar la excepción?
Solución
Su problema es que estás pasando fiel a Marshal.StructureToPtr por lo que los intentos para liberar a los dos punteros de cadena (que a veces no son válidos). Tiene que pasar falsa en este caso ya que sólo se asigna esa memoria en el montón. (Es decir, no hay nada para liberar allí).
Otros consejos
¿Está seguro Marshal.Sizeof (bufItem) y Marshal.Sizeof (FolderInfo) son los mismos?
Y, tal vez el hecho de que no se está inicializando los hilos? Puesto que usted dice que no recibe el error cuando están IntPtr (que por defecto es IntPtr.Zero), que iba a tratar el establecimiento de los dos para cadenas vacías antes de intentar el cálculo de referencias del elemento de amortiguación.
[Editar]
Tal vez usted debe tratar de fijar el mango de amortiguamiento, y el cálculo de referencias que a la estructura, en lugar de en relación inversa. Algo como esto:
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
Usar la palabra clave fija para obtener un puntero a su folderInfo
originales.
Podría ser que los recursos no administrados no están siendo liberados por algo. Comprobar para ver si hay algo que está utilizando implementos IDisposable y si es así, lo envuelve en un bloque using { }
.