Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Alpha ops con spritebatch para conseguir luces en 2D

Iniciado por Hans, 01 de Marzo de 2011, 01:59:44 PM

« anterior - próximo »

Hans

#45
¿Por qué no son comparables si devuelven el mismo resultado (al menos en mi contexto)?

Sobre tu pregunta no he mirado en C# por si te refieres exactamente a eso pero supongo que la diferencia radica en acceder directamente al valor de la variable o acceder a la dirección de memoria en la que está la variable. Lo que viene a ser un puntero en C++, aunque en C# hay además punteros (que no uso porque el Unsafe Code no parece estar muy recomendado y en WP7 directamente no se puede ni compilar). Al menos así lo he entendido desde que uso C# y difiere en nada de cómo lo vengo haciendo en C++. Vaya, como en Java.

El único problema que he tenido a este respecto ha sido en Java, y es que no existe un método simple de copiar el contendido de un puntero en plan p.clone(p2), hay que hacer una movida del cojón para conseguirlo (al menos cuando yo lo miré). En C# no me ha hecho falta clonar nada.

Vicente

Cita de: Hans en 06 de Marzo de 2011, 09:38:18 PM
¿Por qué no son comparables si devuelven el mismo resultado (al menos en mi contexto)?

Tu primera función modifica una variable que parece ser parte de una clase. La segunda crea algo nuevo que puede ser usado en cualquier sitio. Ponme ejemplos de uso de cada una y lo vemos.

Cita de: Hans en 06 de Marzo de 2011, 09:38:18 PM
Sobre tu pregunta no he mirado en C# por si te refieres exactamente a eso pero supongo que la diferencia radica en acceder directamente al valor de la variable o acceder a la dirección de memoria en la que está la variable. Lo que viene a ser un puntero en C++, aunque en C# hay además punteros (que no uso porque el Unsafe Code no parece estar muy recomendado y en WP7 directamente no se puede ni compilar). Al menos así lo he entendido desde que uso C# y difiere en nada de cómo lo vengo haciendo en C++. Vaya, como en Java.

El único problema que he tenido a este respecto ha sido en Java, y es que no existe un método simple de copiar el contendido de un puntero en plan p.clone(p2), hay que hacer una movida del cojón para conseguirlo (al menos cuando yo lo miré). En C# no me ha hecho falta clonar nada.

Ok, no es eso solamente, pero esta explicación me va a llevar un buen rato, supongo que estará mañana...

Vicente

#47
A ver si consigo explicarme... En .NET existen dos tipos diferentes: los tipos por valor y los tipos por referencia. Esta separacion se refiere a como se comportan en el lenguaje, no a como el CLR gestiona la memoria que tienen asociada: los tipos por valor se copian por valor, y en los tipos por referencia lo que se utiliza la referencia.

Normalmente, eso es lo unico que hace falta saber para utilizar un tipo por valor o por referencia. Por ejemplo se recomienda que los tipos por valor sean pequeños porque se copian en las llamadas a las funciones y si son muy grandes (más de 32 bits que es lo que ocupa una referencia en x86) pues pueden dar problemas de rendimiento. Por eso en XNA la librería matemática usa métodos con ref y out, para evitarse copiar matrices (que son mucho más grandes que una referencia a la misma matriz).

Ahora, en XNA nos intenresa saber como funciona el modelo de memoria de .NET porque el GC es bastante malo. En el Compact Framework el GC es simplemente Mark & Sweep (http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)#Na.C3.AFve_mark-and-sweep) mientras que el de escritorio es generacional (http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)#Generational_GC_.28ephemeral_GC.29) y a partir de .NET 4 concurrente (http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)#Stop-the-world_vs._incremental_vs._concurrent).

Después de todo esto llegamos a las reglas de como un tipo interactua con el modelo de memoria de .NET:

- los tipos por referencia siempre se crean en el heap.
- los tipos por valor se crean dentro del contexto donde se declaran.

Para los tipos por referencia es fácil de entender. Cada objeto por referencia para el GC es una cosa que se llama "GC root" que es lo que le indica al GC que lo tiene que vigilar para saber cuando liberar su memoria.

Los tipos por valor en cambio son un poco más raros. Se pueden crear en el stack si son variables locales, parámetros a métodos,... O pueden vivir en el heap si son parte de otra cosa: un tipo por referencia como un enemigo que tiene un vector con su posición, que a su vez tiene tres floats con las coordenadas.

Si nos damos cuenta, he dicho "dentro", es decir, aun creándonse en el heap, el GC no se tiene que preocupar de ellos porque no generan un "GC root": son parte de un objeto más grande que ya está referenciado y manejado por el GC.

La guía de programación de C# lo dice de forma más técnica:

Citar
Value types derive from System.ValueType, which derives from System.Object. Types that derive from System.ValueType have special behavior in the CLR. Value type variables directly contain their values, which means that the memory is allocated inline in whatever context the variable is declared. There is no separate heap allocation or garbage collection overhead for value-type variables.

Resumiendo, que para el GC los tipos por valor son totalmente ignorables (no es 100% cierto porque cuanto más grande un objeto más cuesta moverlo y si es suficientemente grande se trata de forma especial, pero vamos, como si lo fuera). No pueden forzar un proceso de recolección, no lo hacen más lento, ni nada de nada.

Pero es importante recordar que esto es un detalle de implementación y una optimizacion que el CLR hace por nosotros (nada impediría a MS hacer un CLR donde los tipos por valor también se crean por defecto en el heap con un GC Root). En XNA nos hace falta conocer todo esto por otro detalle de implementación (esta vez del GC), pero en un mundo ideal (el PC :p) tampoco habría que volverse muy locos con este tema.

MrK

Citar
Claro, y para mi es ridículo tener que preocuparme de liberar la memoria a mano para evitar que mi juego reviente máquinas una detrás de otra ;) En proyectos grandes prefiero mil veces pagar el coste de rendimiento del GC y no tener memory leaks que tener que preocuparme de buscar ese tipo de problemas.

Además, el miedo a "generar basura" no es un problema del GC en sí, es la implementación actual del GC en Xbox360 y en WP7. En PC no te tienes que preocupar por nada de nada. Y si algún día cambian como está en Xbox360 y en WP7 pues lo mismo (te aseguro que llevamos mucho tiempo pidiendo esto al equipo de XNA, pero de momento ni caso :'( ).

la diferencia esta en que si un juego en C++ rebienta maquinas una detras de otra por culpa de la memoria es culpa mia por no gestionar la memoria bien, mientras que se me antoja dificil darme la culpa de tener un paron cada 5 segundos porque he usado un String.format para imprimir el score...

Y si, para programas complejos y grandes (que no sean juegos) no te discutire que un GC pueda ser util, pero es que tienes juegos en el store que son un "pong" y tienen ese problema, por mucho que el GC de la 360 sea una basura te da a pensar que tipo de "ingenieros despreocupados" estas formando.

En fin, como tu dices, para gustos los colores.


Vicente

Cita de: MrK en 09 de Marzo de 2011, 06:56:24 PM
Y si, para programas complejos y grandes (que no sean juegos) no te discutire que un GC pueda ser util, pero es que tienes juegos en el store que son un "pong" y tienen ese problema, por mucho que el GC de la 360 sea una basura te da a pensar que tipo de "ingenieros despreocupados" estas formando.

Y porque no para juegos tambien? Cualquier aplicacion se puede beneficiar del GC.

blau

Yo quizas sea porque tengo mis manias a la hora de las estructuras de datos, pero no he tenido problemas de rendimeinto en la xbox achacables al GC.

Mis premisas son:

1. Los diccionarios son la peste.... salvo que sean poco frecuentados.
2. En una clase que vaya a ser muy usada no definir referencias a otros objetos directamente, sino a través de un indice entero... para que el GC no se pierda comprobando vinculos cuando liberas
3. Los sistemas de partículas que es lo unico que entre frame y frame puede crear y destruir muchos objetos, con array de structs.
4. No hacer el bestia

Tampoco es que hable como gran experto... pero es mi experiencia...  ^_^'

Vicente

Tambien podrias usar un pool de objetos para las particulas y no andarias creando y destruyendo nada :)

fjfnaranjo

Cita de: Vicente en 09 de Marzo de 2011, 07:18:40 PM
Cita de: MrK en 09 de Marzo de 2011, 06:56:24 PM
Y si, para programas complejos y grandes (que no sean juegos) no te discutire que un GC pueda ser util, pero es que tienes juegos en el store que son un "pong" y tienen ese problema, por mucho que el GC de la 360 sea una basura te da a pensar que tipo de "ingenieros despreocupados" estas formando.

Y porque no para juegos tambien? Cualquier aplicacion se puede beneficiar del GC.

Umh, aquí voy a opinar yo un poquito.

El GC es una buena solución para un conjunto genérico grande de aplicaciones, pero se me ocurren muchísimos ejemplos de aplicaciones donde una gestión manual de la memoria es imprescindible. Y sí, los juegos, en cuanto se vuelven ambiciosos, empiezan a necesitar ese mantenimiento manual...
fjfnaranjo.com - Creating entertainment - Creando entretenimiento
fjfnaranjo [4t] gm4il [d0t] c0m (mail y msn)

Vicente

La cruda realidad es que el GC maneja la memoria mejor que la mayoria de los programadores.

Lo de que hace falta el manejo manual lo he escuchado muchas veces desde el lado del sector no-manejado, pero algun argumento convincente para soportar esa afirmacion? (curiosidad, nunca he visto ninguno).

Vicente

Y ademas de la explicacion tecnica de porque es imprescindible, estaria ya de nota si se añadiera que cosas se suelen hacer en C++ cuando hablamos de "manejo manual" (es realmente a pelo? o se cambia el new, las asignaciones y otras perrerías del estilo?).

fjfnaranjo

No hombre, no hay perrerías. Se programa bien, de forma profesional y organizada. Se diseña correctamente la aplicación para que la gestión de memoria sea parte de la misma, y no un "problema" a resolver por un tercero (lease GC u otras cosas).

Un ejemplo no te puedo poner porque no es un tema precisamente simple. Pero no es tan sólo usar un delete por cada new que haya. Es que se diseña teniendo en cuenta la memoria. Hay operadores que tienen funciones relacionadas con la forma en la que se van a organizar los datos en la aplicación (const, volatile...), no se separa el concepto de memoria de variable y memoria de objeto, si no que se entiende en conjunto como la aplicación trabaja y se diseña con esa perspectiva en la cabeza.

También se sabe que existe un coste de instanciado, y se diseña teniéndolo en cuenta, con pools y otros patrones similares.

No te digo que sea imprescindible porque me lo este inventando. Imáginate un juego FPS AAA moderno, de los de consola, piensa en las partículas que hay, la IA que lleva por debajo, las paridas de iluminación, etc... Cuando las cosas se ponen duras no te puedes permitir depender de un GC, que no sabes exacta y precisamente lo que hace, o que mantiene los objetos en la memoria ad infinitun porque haya un par de hilos de la aplicación que no sabe si va a usarlos o no.

Y ya no te hablo de software médico, o de la aplicación que gestiona el frenado de emergencia del AVE... No te estoy diciendo que el GC no tenga usos, precisamente te he dicho que los tiene y muy variados, pero no te creas que eso resuelve definitivamente el tema de la memoria y que todo podría afrontarse con un sistema de gestión dinámica de la misma. Hay casos para los que sí, y casos para los que no.

Desde mi punto de vista, cuanto más te acercas a forzar un sistema hasta su límite, mas detallista tienes que ser con como programas para el mismo. Obviamente, si quieres hacer un port del Monkey Island, con las máquinas que hay hoy en día, los nucleos que tienen y los pedazo de bloques de RAM, vamos, te puedes permitir incluso no liberar memoria, si no ir dejando innertes los objetos por ahí tirados (si luego va mal el sistema, pues se reinicia y ya xD).

Y que el GC gestione mejor la memoria que la mayoría de los programadores no es un argumento, simplemente estás diciendo que hay muchos programadores malos. Y eso vamos, es un hecho, y te lo puedo jurar si quieres. A más de uno que he conocido le hacía comerse su título universitario y la orla en papel fotográfico ya de paso...
fjfnaranjo.com - Creating entertainment - Creando entretenimiento
fjfnaranjo [4t] gm4il [d0t] c0m (mail y msn)

Vicente

#56
La gestion de memoria es un problema a resolver en todas las aplicaciones. Y en las aplicaciones grandes la mayoria de la gente lo resuelve mal. En mi opinion no es porque sean malos programadores como dices tu, es que es un problema muy jodido. Pero aun resolviendolo mal, esa gente saca al mercado sistemas operativos, juegos AAA,... y aqui paz y despues gloria. No hace falta la perfección para sacar algo.

El GC es uno de esos puntos en la informática en la que nos toca platearnos si hay herramientas que hacen mejor nosotros cierto trabajo.  Otro ejemplo serían los compiladores. Seguro que hay gente que sabe un huevo que es capaz de sacar codigo mejor que el que genera el compilador, pero no creo que sea imprescindible a dia de hoy para sacar un AAA.

Tambien puede ser que estes pirao por el rendimiento, pero estos son casos muy raritos. Por ejemplo, la gente de Crytek en el CDV dijo que para el Crysis 2 usarian C++ como lenguaje de scripting porque si no no podian sacar todo el rendimiento que necesitaban. Estupendo, pero tampoco necesitas llegar a eso para hacer un AAA.

Para mi, excepto casos rarunos (como lo del Crysis 2), la mayoría de los AAA de hoy en día se podrían hacer con un GC sin problemas. Ciertas cosas las tendrías que diseñar pensando que usas un GC (como por ejemplo lo que hablaba blau de las partículas) y listo.

blau

Toda la IA de Los Sims 3 esta hecha en C#, corre bajo mono, durante el desarrolllo tenia todas las opciones de seguridad y chequeo activadas, y una vez libre de fallos, le desactivaron la comprobación de rango en arrays y otros temas para obtener mas rendimiento.

Lo que decían es que el tiempo de desarrollo se redujo bastante... y el impacto en rendimiento fue muy bajo.


Buscando el post donde leí eso, para contrastarlo me he topado con un post reciente de miguel de icaza sobre la gdc, bastante extenso por cierto, que arroja mucha luz sobre el devenir de C# y el desarrollo de videojuegos.

http://tirania.org/blog/archive/2011/Mar-07.html

blau

Acabo de toparme con el await y el async de c# 5, y me he quedao de piedra,

http://danielcaceresm.com/blog/index.php/programacion/novedades-c-y-la-programacin-asncrona/

una idea dencilla, que va a mejorar la vida de todos los programadores de c#.

Anders rules!!!

MrK

Cita de: Vicente en 09 de Marzo de 2011, 11:37:12 PM
La cruda realidad es que el GC maneja la memoria mejor que la mayoria de los programadores.

Al menos me alegro de ser de la minoria que se apaña mejor sin el GC, porque me ha dado mas problemas el GC el ultimo mes que todas las aplicaciones que he desarrollado en el trabajo y juegos a horas libres en 5 años. :)

Por que no para juegos? Pues porque en el 99% de las aplicaciones desarrolladas te da igual que una cosa te tarde 100 milis mas pues quizas te estas tirando 3 minutos en una query, pero si tienes que generar un frame cada 16 milis eso requiere un control estricto de la maquina que hay debajo. Personalmente no aguanto juegos con tirones o bajones de framerate (pero bueno, este tipo de juegos desde que las consolas se parecen a un PC esta desapareciendo)

Que en un futuro el GC sea mejor para 360/360 next/WP7? Eso no te lo discuto. Pero ahora como ahora, no.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.