¿La gestión de la memoria en la programación se está convirtiendo en una preocupación irrelevante?
La administración de la memoria (o control) es en realidad la razón principal por la que estoy usando C y C ++.
La memoria es relativamente barata ahora.
No es memoria rápida. Todavía estamos viendo una pequeña cantidad de registros, algo así como caché de datos de 32 KB para L1 en i7, 256 KB para L2 y 2 MB para L3 / core. Eso dijo:
Si no hablamos en términos de plataformas de destino con límites estrictos en la memoria de trabajo (es decir, sistemas embebidos y similares), ¿debería ser una preocupación el uso de la memoria al elegir un lenguaje de uso general en la actualidad?
Uso de memoria en un nivel general, tal vez no. Soy un poco poco práctico en el sentido de que no me gusta la idea de un bloc de notas que tome, digamos, 50 megabytes de DRAM y cientos de megabytes de espacio en el disco duro, aunque tengo eso de sobra y abundante. He estado presente por mucho tiempo y me parece extraño y un poco desagradable ver que una aplicación tan simple requiere relativamente tanta memoria para lo que debería ser posible con kilobytes. Dicho esto, podría vivir conmigo mismo si me encontrara con algo así si aún fuera agradable y receptivo.
La razón por la que la administración de memoria es importante para mí en mi campo no es reducir el uso de memoria en general. Cientos de megabytes de uso de memoria no necesariamente retrasarán una aplicación de una manera no trivial si no se accede a ninguna de esa memoria con frecuencia (por ejemplo, solo al hacer clic en un botón o alguna otra forma de entrada del usuario, que es extremadamente infrecuente a menos que usted están hablando de jugadores coreanos de Starcraft que podrían hacer clic en un botón un millón de veces por segundo).
La razón por la que es importante en mi campo es mantener la memoria apretada y muy cerca, a la que se accede con mucha frecuencia (por ejemplo, estar en bucle en cada cuadro) en esas rutas críticas. No queremos perder un caché cada vez que accedemos a solo uno de un millón de elementos a los que se debe acceder en un bucle en cada cuadro. Cuando bajamos la memoria de la jerarquía de la memoria lenta a la memoria rápida en grandes fragmentos, digamos líneas de caché de 64 bytes, es realmente útil si esos 64 bytes contienen datos relevantes, si podemos encajar múltiples elementos en esos 64 bytes, y si nuestros patrones de acceso son tales que los usamos todos antes de que se desalojen los datos.
Esos datos a los que se accede con frecuencia para el millón de elementos solo pueden abarcar 20 megabytes aunque tengamos gigabytes. Todavía hace un mundo de diferencia en las velocidades de cuadros que se repiten sobre esos datos cada cuadro dibujado si la memoria está apretada y estrecha para minimizar las fallas de caché, y ahí es donde la administración / control de la memoria es tan útil. Ejemplo visual simple en una esfera con algunos millones de vértices:
Lo anterior es en realidad más lento que mi versión mutable, ya que está probando una representación persistente de la estructura de datos de una malla, pero aparte de eso, solía tener dificultades para lograr tales velocidades de cuadros incluso en la mitad de esos datos (es cierto que el hardware se ha vuelto más rápido desde mis dificultades) ) porque no aprendí a minimizar los errores de caché y el uso de memoria para datos de malla. Las mallas son algunas de las estructuras de datos más complicadas con las que he tratado a este respecto porque almacenan tantos datos interdependientes que tienen que estar sincronizados, como polígonos, bordes, vértices, tantos mapas de textura como el usuario quiera adjuntar, pesos óseos, mapas de colores, conjuntos de selección, objetivos de transformación, pesos de borde, materiales poligonales, etc., etc., etc.
He diseñado e implementado una serie de sistemas de malla en las últimas dos décadas y su velocidad fue a menudo muy proporcional al uso de su memoria. Aunque estoy trabajando con mucha más memoria que cuando comencé, mis nuevos sistemas de malla son 10 veces más rápidos que mi primer diseño (hace casi 20 años) y en gran medida porque usan alrededor de 1/10 de la memoria. La versión más reciente incluso utiliza compresión indexada para acumular la mayor cantidad de datos posible, y a pesar de la sobrecarga de procesamiento de la descompresión, la compresión en realidad mejoró el rendimiento porque, nuevamente, tenemos muy poca memoria rápida preciosa. Ahora puedo ajustar un millón de mallas poligonales con coordenadas de textura, arrugas de bordes, asignaciones de materiales, etc. junto con un índice espacial para ello en aproximadamente 30 megabytes.
Aquí está el prototipo mutable con más de 8 millones de cuadrángulos y un esquema de subdivisión multires en un i3 con un GF 8400 (esto fue de hace algunos años). Es más rápido que mi versión inmutable, pero no se usa en producción ya que he encontrado que la versión inmutable es mucho más fácil de mantener y el impacto en el rendimiento no es tan malo. Tenga en cuenta que la estructura de alambre no indica facetas, sino parches (los cables son en realidad curvas, de lo contrario toda la malla sería negra), aunque el pincel modifica todos los puntos de una faceta.
De todos modos, solo quería mostrar algo de esto arriba para mostrar algunos ejemplos concretos y áreas donde la administración de memoria es tan útil y, con suerte, para que la gente no piense que estoy hablando de mi trasero. Tiendo a irritarme un poco cuando la gente dice que la memoria es tan abundante y barata, porque se trata de memoria lenta como DRAM y discos duros. Todavía es tan pequeño y tan valioso cuando hablamos de memoria rápida, y el rendimiento para rutas realmente críticas (es decir, caso común, no para todo) se relaciona con jugar a esa pequeña cantidad de memoria rápida y utilizarla de la manera más efectiva posible. .
Para este tipo de cosas, es realmente útil trabajar con un lenguaje que le permita diseñar objetos de alto nivel como C ++, por ejemplo, y al mismo tiempo poder almacenar estos objetos en una o más matrices contiguas con la garantía de que la memoria de Todos estos objetos estarán representados de manera contigua y sin sobrecarga de memoria innecesaria por objeto (por ejemplo: no todos los objetos necesitan reflexión o despacho virtual). Cuando realmente se muda a esas áreas críticas para el rendimiento, en realidad se convierte en un aumento de la productividad tener ese control de memoria sobre, por ejemplo, jugar con grupos de objetos y usar tipos de datos primitivos para evitar sobrecarga de objetos, costos de GC y mantener la memoria a la que se accede con frecuencia juntos contiguos
Por lo tanto, la gestión / control de la memoria (o la falta de ella) es en realidad una razón dominante en mi caso para elegir qué idioma de manera más productiva me permite abordar los problemas. Definitivamente escribo mi parte de código que no es crítico para el rendimiento, y para eso tiendo a usar Lua, que es bastante fácil de incrustar desde C.