Pregunta Gestión de la memoria C #: palabras clave y punteros inseguros


¿Cuáles son las consecuencias (positivas / negativas) del uso del inseguro palabra clave en DO# usar punteros? Por ejemplo, ¿qué pasa con la recolección de basura, cuáles son las ganancias / pérdidas de rendimiento, cuáles son las ganancias / pérdidas de rendimiento en comparación con la gestión de memoria manual de otros idiomas, cuáles son los peligros, en qué situación es realmente justificable hacer uso de este lenguaje? característica, ¿es más largo para compilar ...?


32
2018-03-22 22:30


origen


Respuestas:


Como ya mencionó Conrad, hay algunas situaciones donde el acceso inseguro a la memoria en C # es útil. No hay como muchos de ellos, pero hay algunos:

  • Manipulando con Bitmap es casi un ejemplo típico en el que necesita un rendimiento adicional que puede obtener mediante el uso de unsafe.

  • Interoperabilidad con una API más antigua (como WinAPI o DLL C / C ++ nativas) es otra área donde unsafe puede ser bastante útil; por ejemplo, puede querer llamar a una función que toma / devuelve un puntero no administrado.

Por otro lado, puedes escribir la mayoría de las cosas usando Marshall clase, que oculta muchas de las operaciones inseguras dentro de las llamadas a métodos. Esto será un poco más lento, pero es una opción si quieres evitar el uso unsafe (o si está usando VB.NET que no tiene unsafe)

Consecuencias positivas: Entonces, las principales consecuencias positivas de la existencia de unsafe en C # es que puedes escribir algún código más fácilmente (interoperabilidad) y puedes escribir un código de manera más eficiente (manipulando con mapa de bits o tal vez algunos cálculos numéricos pesados ​​usando matrices, aunque no estoy tan seguro del segundo).

Consecuencias negativas: Por supuesto, hay algún precio que debe pagar por usar unsafe:

  • Código no verificable: Código de C # que se escribe utilizando el unsafe las características se vuelven no verificables, lo que significa que su código podría comprometer el tiempo de ejecución de alguna manera. Este no es un gran problema en un plena confianza escenario (por ejemplo, aplicación de escritorio no restringida): simplemente no tiene todas las buenas garantías .NET CLR. Sin embargo, no puede ejecutar la aplicación en un entorno restringido, como alojamiento web público, Silverlight o confianza parcial (por ejemplo, aplicación que se ejecuta desde la red).

  • Recolector de basura también debe tener cuidado cuando usa unsafe. GC generalmente se permite reubicar objetos en el montón administrado (para mantener la memoria desfragmentada). Cuando toma un puntero a algún objeto, necesita usar fixed palabra clave para decirle al CG que no puede mover el objeto hasta que termine (lo que probablemente podría afectar el rendimiento de la recolección de basura, pero por supuesto, dependiendo del escenario exacto).

Supongo que si C # no tuviera que interoperar con código anterior, probablemente no sería compatible unsafe (y los proyectos de investigación como Singularity que intentan crear un sistema operativo más verificable basado en lenguajes administrados definitivamente no permiten el uso de un código seguro). Sin embargo, en el mundo real, unsafees útil en algunos casos (raros).


26
2018-04-01 18:20



Puedo darte una situación en la que valga la pena usar:

Tengo que generar un mapa de bits píxel por píxel. Drawing.Bitmap.SetPixel() es demasiado lento Así que construyo mi propio administrado Array de datos de mapa de bits y uso unsafe para obtener el IntPtr para Bitmap.Bitmap( Int32, Int32, Int32, PixelFormat, IntPtr).


8
2018-03-22 23:39



Para citar Professional C # 2008:

"Las dos razones principales para usar   los punteros son:

  1. Compatibilidad hacia atrás - A pesar de todas las facilidades proporcionadas por el   .NET-runtime todavía es posible   llamar a funciones API nativas de Windows, y   para algunas operaciones este puede ser el   única manera de realizar su tarea.   Estas funciones API son generalmente   escrito en C y a menudo requieren   punteros como parámetros. Sin embargo, en   muchos casos es posible escribir el   DllImport declaración de una manera que   evita el uso de punteros; por ejemplo,   mediante el uso de la clase System.IntPtr.
  2. Actuación - En esas ocasiones donde la velocidad es máxima   importancia, el puntero puede proporcionar una   ruta a rendimiento optimizado. Si tu   sabe lo que está haciendo, puede   asegurar que se acceda a los datos o   manipulado de la manera más eficiente.   Sin embargo, tenga en cuenta que, con mayor frecuencia   que no, hay otras áreas de   tu código donde puedes hacer necesario   mejorar el rendimiento sin   resoirting a punteros. Intenta usar un   analizador de código para buscar cuellos de botella   en tu código, uno viene con Visual   Studio 2008. "

Y si usa el puntero, su código requerirá una mayor palanca de confianza para ejecutar y si el usuario no garantiza que su código no se ejecutará.

Y termine con una última cita:

"Recomendamos encarecidamente no usar   punteros innecesariamente porque lo hará   no solo será más difícil escribir y depurar,   pero también fallará la memoria   controles de seguridad de tipo impuestos por   CLR ".


4
2018-03-22 22:49



La recolección de basura es ineficiente con objetos de larga vida. El recolector de basura de .Net funciona mejor cuando la mayoría de los objetos se lanzan rápidamente, y algunos objetos "viven para siempre". El problema es que los objetos de vida más larga solo se lanzan durante las recolecciones de basura completas, lo que implica una importante penalización del rendimiento. En esencia, los objetos de larga vida pasan rápidamente a la generación 2.

(Para obtener más información, es posible que desee leer en el recolector de basura generacional de .Net: http://msdn.microsoft.com/en-us/library/ms973837.aspx)

En situaciones en las que los objetos, o el uso de la memoria en general, va a durar mucho tiempo, la gestión manual de la memoria producirá un mejor rendimiento porque puede liberarse al sistema sin requerir una recolección completa de basura.

Implementar algún tipo de sistema de administración de memoria basado en una sola matriz de bytes grandes, estructuras y mucha aritmética de punteros podría teóricamente aumentar el rendimiento en situaciones donde los datos se almacenarán en RAM durante mucho tiempo.

Lamentablemente, no conozco una buena forma de hacer una gestión de memoria manual en .Net para objetos que durarán mucho tiempo. Esto básicamente significa que las aplicaciones que tienen datos de larga duración en la RAM perderán periódicamente su capacidad de respuesta cuando ejecuten una recolección completa de basura de toda la memoria.


1
2017-08-16 08:43