Pregunta

Digamos que desea escribir un método de alto rendimiento que procese un conjunto de datos grande. ¿Por qué los desarrolladores no deberían tener la capacidad de activar la gestión de la memoria manual en lugar de ser obligados a moverse a C o C ++?

void Process()
{
    unmanaged
    {
        Byte[] buffer;
        while (true)
        {
            buffer = new Byte[1024000000];

            // process

            delete buffer;
        } 
    }   
}
¿Fue útil?

Solución

Porque permitirle eliminar manualmente un bloque de memoria, mientras que aún puede haber referencias a él (y el tiempo de ejecución no tiene forma de saber que sin hacer un ciclo GC) puede producir punteros colgantes y, por lo tanto, se rompe seguridad de la memoria. Los idiomas de GC son generalmente seguros de memoria por diseño.

Dicho esto, en C#, en particular, puedes hacer lo que quieras ya:

void Process()
{
    unsafe
    {
        byte* buffer;
        while (true)
        {
            buffer = Marshal.AllocHGlobal(1024000000);

            // process

            Marshal.FreeHGlobal(buffer);
        } 
    }   
}

Tenga en cuenta que, como en c/c ++, tiene aritmética de puntero completo para tipos de puntero bruto en C# - Entonces buffer[i] o buffer+i son expresiones válidas.

Otros consejos

Si necesita un alto rendimiento y un control detallado, tal vez debería escribir lo que está haciendo en C o C ++. No todos los idiomas son buenos para todas las cosas.

Editado para agregar: un solo idioma no será bueno para todas las cosas. Si suma todas las funciones útiles en todos los buenos lenguajes de programación, obtendrá un desastre realmente grande, mucho peor que C ++, incluso si puede evitar la inconsistencia.

Las características no son gratuitas. Si un idioma tiene una característica, es probable que las personas la usen. No podrá aprender C# lo suficientemente bien sin aprender las nuevas rutinas de gestión de memoria manual de C#. Los equipos de compiladores lo implementarán, a costa de otras características del compilador que son útiles. Es probable que el lenguaje sea difícil de analizar como C o C ++, y eso conduce a una compilación lenta. (Como chico C ++, siempre me sorprende cuando compilo uno de nuestros proyectos C#. La compilación parece casi instantánea).

Las características entran en conflicto entre sí, a veces de manera inesperada. C90 no puede hacerlo tan bien como Fortran en los cálculos de matriz, ya que la posibilidad de que los punteros C estén alias eviten algunas optimizaciones. Si permite la aritmética del puntero en un idioma, debe aceptar sus consecuencias.

Está sugiriendo una extensión de C# para permitir la gestión de la memoria manual, y en algunos casos sería útil. Eso significaría que la memoria tendría que ser asignada de manera separada, y tendría que haber una forma de contar la memoria administrada manualmente de la memoria administrada automáticamente. De repente, ha complicado la gestión de la memoria, hay más posibilidades de que un programador se endurezca, y el administrador de memoria en sí es más complicado. Está obteniendo un poco de rendimiento que importa en algunos casos a cambio de una mayor complicación y una gestión de memoria más lenta en todos los casos.

Puede ser que en algún momento tendremos un lenguaje de programación que sea bueno para casi todos los propósitos, desde secuencias de comandos hasta crujientes de números, pero no hay nada popular que esté cerca de eso. Mientras tanto, tenemos que estar dispuestos a aceptar las limitaciones de usar solo un idioma, o el desafío de aprender varios y cambiar entre ellos.

En el ejemplo que publicó, ¿por qué no simplemente borrar el búfer y reutilizarlo?

El recolector de basura .NET es muy bueno para resolver qué objetos ya no se hace referencia y libera la memoria asociada de manera oportuna. De hecho, el recolector de basura tiene un montón especial (el montón de objeto grande) en el que pone objetos grandes como este, que está optimizado para tratar con ellos.

Además de esto, no permitir que las referencias se liberen explícitamente simplemente elimina una gran cantidad de errores con fugas de memoria y punteros colgantes, que conducen a un código mucho más seguro.

Liberar cada bloque no utilizado individualmente como se hace en un idioma con una gestión de memoria explícita puede ser más costoso que dejar que un recolector de basura lo haga, porque el GC tiene la posibilidad de usar esquemas de copia para pasar un tiempo lineal a la cantidad de bloques que quedan vivos (o El número de bloques recientes quedó vivo) en lugar de tener que manejar cada bloque muerto.

La misma razón por la que la mayoría de los núcleos no le permitirán programar sus propios hilos. Porque el 99.99+% del tiempo que realmente no necesitas, y exponer esa funcionalidad el resto del tiempo solo te tentará a hacer algo potencialmente estúpido/peligroso.

Si realmente necesita un control de memoria de grano fino, escriba esa sección de código en otra cosa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top