2010-10-13 15 views
9

Estoy teniendo un poco de confusión, esta es una pregunta muy tonta.Gestión de la memoria del componente no administrado Por CLR

¿dónde se asigna la memoria para un componente no administrado?

En mi código .net si inicié un componente no administrado, ¿dónde se cargará este componente y se asignará la memoria?

¿Cómo llama CLR Marshall entre el montón Gestionado y No gestionado?

EDITAR

Gracias por su respuesta, pero lo que estoy preguntando es digo supongo que sí un dllimport de USER32.DLL, esto es claramente una DLL no administrado y me llaman a alguna función en USER32.DLL ahora mi pregunta , ¿cómo CLR coordina mi llamada a este dll no gestionado?

Respuesta

10

Comienza bastante fácil. El marshaller de pinvoke primero llama a LoadLibrary y le pasa el nombre de DLL que usted especificó, la propiedad DllImportAttribute.Value. En su caso, user32.dll ya está cargado porque se carga por el iniciador de .NET, su recuento de referencia se incrementa. Pero normalmente el cargador de Windows obtiene la DLL asignada en el espacio de direcciones del proceso para que se puedan llamar las funciones exportadas.

El siguiente es GetProcAddress para obtener la dirección de la función para llamar, la propiedad DllImportAttribute.EntryPoint. El marshaller hace un par de intentos a menos que uses ExactSpelling. Un nombre de función como "foo" se prueba de varias maneras posibles, foo y fooW o fooA. Detalles desagradables de implementación de Win32 relacionados con la diferencia entre los caracteres Unicode y Ansi. La propiedad CharSet es importante aquí.

Ahora necesito agitar las manos un poco porque se pone complicado. El Marshal construye un marco de pila, configurando los argumentos que necesitan pasar a la función exportada. Esto requiere un código de bajo nivel, cuidadosamente excluido de las miradas indiscretas. Tómese el valor nominal de que realiza el tipo de traducciones que admite la clase Marshal para convertir entre tipos administrados y no administrados. La propiedad DllImportAttribute.CallingConvention importa aquí porque eso determina qué valor de argumento debe colocarse donde para que la función llamada pueda leerlo correctamente.

A continuación, configura un manejador de excepciones SEH para que las excepciones de hardware generadas por el código llamado se puedan capturar y traducir a una excepción administrada. El que genera el más común, AccessViolationException. Y otros.

A continuación, empuja una cookie especial en la pila para indicar que el código no administrado está a punto de comenzar a usar la pila. Esto evita que el recolector de basura se meta en marcos de pila no gestionados e interprete los punteros que encuentra allí como referencias de objetos gestionados. Puede volver a ver esta cookie en la pila de llamadas del depurador, [Transición de administrado a nativo].

A continuación, solo una llamada indirecta a la dirección de función que se encuentra con GetProcAddress(). Eso hace que se ejecute el código no administrado.

Después de la llamada, es posible que sea necesario realizar una limpieza para liberar la memoria que se asignó para pasar los argumentos no administrados. El valor de retorno podría necesitar ser traducido nuevamente a un valor administrado. Y eso es todo, suponiendo que nada desagradable sucediera, la ejecución continúa en la siguiente declaración del código administrado.

8

Las asignaciones de memoria no gestionadas provienen del montón de procesos. Usted es responsable de asignar/desasignar la memoria, ya que no se recogerá la basura porque el GC no conoce estos objetos.

+0

Es posible que desee crear un envoltorio alrededor del componente no administrado, e implementar la interfaz 'IDisposable', de una forma más limpia de deslocalizarlo. El recolector de basura llama a la función definida en esta interfaz para evitar que se "olvide" limpiar. –

+1

Puede envolverlo en IDisposable, pero asegúrese de llamar a Dispose o anular el finalizador. Simplemente implementar IDispose no es suficiente, el GC no llama a Dispose, sino a Object.Finalize (ver http://stackoverflow.com/questions/45036/will-the-gc-call-disposable-dispose-for-me) – pstrjds

0

Parte de su pregunta es respondida por Michael. Respondo la otra parte.

Si CLR se carga en un proceso no administrado, se denomina alojamiento CLR. Esto generalmente implica llamar a un punto de entrada en mscoree DLL y luego se carga el AppDomain predeterminado. En tal caso, CLR solicita un bloque de memoria del proceso y, cuando se da, se convierte en su espacio de memoria y tendrá una pila y un montón.

1

Del mismo modo que una pieza académica de información en expansión en lo que se ha publicado aquí:

Hay alrededor de 8 diferentes montones de que el CLR utiliza:

  1. cargador Montón: contiene estructuras de CLR y el tipo sistema de

  2. alta frecuencia del montón: la estática, la MethodTables, FieldDescs, mapa interfaz

  3. baja Frecu rencia Montón: EEClass, ClassLoader y de búsqueda de tablas

  4. Trozo Heap: boquillas para CAS, contenedores COM, P/Invoke

  5. grande de objetos Montón: las asignaciones de memoria que requieren más de 85k bytes

  6. GC montón: la memoria de usuario montón asignado privado a la aplicación

  7. código JIT montón: memoria asignada por mscoreee (motor de ejecución) y el compilador JIT para el código administrado

  8. Proceso/Base Montón: interoperabilidad/asignaciones no administrados, la memoria nativa, etc

HTH

Cuestiones relacionadas