Acerca de...
El equipo
Encuestas
Política de privacidad
WinTablets

Encuesta

¿Cual crees que triunfará?

Ver Resultados

Cargando ... Cargando ...

últimas entradas importantes

Categorías

Archivos

21
Jul 2014
DesarrolloGuíasMetroModern UIrfogdevSoftwareTrucos

Modelo de lanzamiento/cierre de las aplicaciones Modern UI

En esta entrada os voy a explicar cómo funciona la carga de aplicaciones Modern UI. Lo que ocurre desde que tocas en pantalla un cuadradito hasta que tienes la aplicación funcional, amén de cómo se quedan en memoria y se recuperan en siguientes instancias. No será una entrada técnica. Vamos allá.

Vamos a partir de una tableta o un ordenador Windows recién arrancado, sin haber ejecutado nada todavía sobre él. En el caso de las tabletas no me refiero a después de haberla encendido del reposo, sino a después de un reinicio.

Ahora tocamos un icono del menú principal, con lo que se inicia la carga del programa. El menú inicio realmente es un programa en sí, que está encargado de mostrarnos los iconos de las aplicaciones que tengamos instaladas y configuradas para tal.

Por lo tanto, cuando detecta un toque en pantalla mira a ver qué icono hay debajo y lanza el programa adecuado mediante la llamada del API de Windows adecuada. Del API de Win32, porque si no me equivoco la aplicación que representa el menú inicio es una aplicación nativa Win32 escrita en C++/CX.

Dentro de Windows hay un módulo que se llama cargador del sistema, y lo que hace es abrir el fichero ejecutable y mirar dentro de él una serie de metadatos para descubrir qué tipo de programa es y ejecutarlo en el entorno adecuado. Si es uno de consola, abrirá el emulador de consola y lo ejecutará. Lo mismo pasa en el caso de ser Win32 ó Win64 y si es PE, NE, o LE. No entramos en detalles sobre esas siglas, simplemente diremos que son tipos de ejecutables Windows que han ido evolucionando a lo largo de la historia del sistema operativo.

Luego están las aplicaciones .NET. Es my raro ver un cuadro de error con el número 135, pero es lo que pasa si no tenemos el .NET Framework instalado. Suele ocurrir bajo Windows XP y Vista, y ya a partir de Windows 7 el sistema es más inteligente y te pregunta si quieres instalar la versión adecuada del .NET a tu programa en caso de no estarlo ya.

Las aplicaciones de la tienda de windows son un tanto especiales, ya que puede haber dos tipos dependiendo de con qué lenguaje se hayan escrito. El entorno Modern UI es nativo y está escrito en C++. Lo que hace es extender Win32 con una serie de nuevas APIs que sólo se pueden usar con este tipo de aplicaciones (en principio). El .NET es, de nuevo, un superconjunto (o más bien una abstracción) sobre esas APIs que ofrecen otras ya dentro de una máquina virtual .NET.

Es decir, si en Win32 tenemos el propio interfaz de programación Win32 (que es C y algo de C++ empaquetado como C), y encima de él el .NET como envoltorio a él, en las aplicaciones Metro tenemos una nueva capa escrita en C++ sobre Win32 llamada WRL y, encima, otra versión de .NET.

Por lo tanto, las aplicaciones de la tienda se pueden escribir en C++ sobre WRL y en C#/VB.NET sobre el motor .NET.

En resumen, que a fecha de hoy tenemos CUATRO interfaces de desarrollo: Win32, WRL, .NET clásico y .NET Modern UI.

Continuando con el proceso de carga, supongamos que nuestra aplicación es la típica de la tienda y está escrita en .NET.

Lo que hace el cargador del sistema es iniciar una máquina virtual .NET (o un entorno de ejecución .NET o como queráis llamarlo). Eso supone procesar un montón de archivos y bibliotecas y, cuando todo está listo, se inicia la carga del programa.

Ese se introduce en memoria, se sacan sus metadatos y se busca el punto de entrada. A partir de ahí comienza un baile muy interesante.

Un ejecutable .NET no es un ejecutable nativo. Contiene lo que tradicionalmente se conoce como P-CODE, aunque si se le renombra a MSIL queda mucho más fashion ya que es algo que existe desde los tiempos de Basic (sin el Visual delante) y seguro que antes.

Lo que contiene, aparte de una serie de metadatos que deben ser interpretados por el cargador, es un pseudo ensamblador que ha de ser compilado a la máquina nativa. La diferencia con otros lenguajes similares está en que, en lugar de ir interpretando (traduciendo a código máquina real) esas instrucciones, se compila al vuelo método a método y clase a clase conforme se va necesitando.

Lo que primero se compila es el punto de entrada. Pero este llama a otros sitios, de modo que tenemos una cadena de pre-compilaciones antes de poder ejecutar el programa.

No obstante llega un momento en el que ya está todo listo para ser ejecutado, aunque durante la ejecución de la aplicación el baile no termina ahí, porque pueden ocurrir varias cosas: que se llegue a un punto en el que el código no esté compilado a nativo y haya que hacerlo, en el que se esté usando mucha memoria y haya que compactarla, o que se vuelva a ejecutar de nuevo código ya compilado.

En el primer caso hay que compilar lo nuevo, lo que lleva tiempo. En el segundo hay que lanzar el recolector de basura, que lleva tanto tiempo que a veces lo tienes que lanzar tu a mano en tu código porque el entorno no se atreve a hacerlo incluso cuando la aplicación da un error de que le falta memoria que se solucionaría llamando a dicho recolector.

El tercero es un poco más complejo, porque puede haber tres nuevas sub-situaciones. La primera consiste en que ante una segunda ejecución, se le vuelve a pasar el compilador/optimizador para mejorar el código, teniendo en cuenta que cuantas más veces se ejecute, más rápido correrá ese código, hasta un que el jitter (el optimizador) ya no sea capaz de mejorarlo. En ese caso entramos en la segunda situación, en la que el código está en memoria y optimizado: se ejecuta sin más. La más molesta de todas es la última, y ocurre cuando el método ha sido eliminado de memoria porque lleva tiempo sin ser ejecutado, y hay que repetir el proceso desde el principio.

Ahora imaginaos todo ese proceso repetido cada vez que lancemos una aplicación y ésta se esté ejecutando. Aparte del consumo de energía, son unas tareas muy lentas que no se notan en un procesador de escritorio pero sí en uno móvil.

Veamos por un momento cómo se ejecutan las aplicaciones escritas en C++ y WRL. Todo el proceso de cargar el sistema es el mismo… excepto que no se carga la máquina virtual .NET, ni el proceso de compilación, ni el compactador de memoria, ni el jitter… Vamos, que es equivalente a un proceso escrito en Win32 pero corriendo dentro de Modern UI.

Como podéis ver, hay una gran diferencia entre una forma y la otra. El problema con C++/CX y WRL es que si ya de por sí desarrollar con C++ es complicado, no os digo con WRL, que apenas está documentado y utiliza algunas cosas de C++ moderno. Y encima los errores del compilador son, cuando menos, abstrusos.

Existe otra ventaja sobre desarrollar con C++/CX que os contaré en otro momento, porque ahora vamos a volver al modelo de ejecución de Modern UI.

¿Qué pasa cuando le damos a la tecla Windows y cerramos la aplicación? Esta no se cierra, sino que se queda residente en memoria pero completamente detenida.  Esto es muy importante aunque no nos explayaremos aquí: completamente detenida. Dependiendo del tipo de aplicación y su tamaño, quedará simplemente suspendida o dejará una huella.

¿Por qué se suspende y no se cierra? Muy sencillo: la próxima vez que lancemos la misma aplicación, gran parte del proceso descrito arriba ya ha sido realizado, y tan solo hay que volver a ejecutar, incluso en el caso de que sólo esté la huella, que es lo que ocurre cuando una aplicación peta y se cierra por algún tipo de error. (¿Capischi, Mahjong?).

Es decir, aunque el programa murió, todo el código precompilado y guardado como nativo, así como las imágenes y el estado del programa, siguen quedando en memoria, de modo que en un posible siguiente lanzamiento el comportamiento de la aplicación es superior incluso al de uno nativo o escrito con C++/CX: buscar el punto de entrada y ejecutar ya que todo lo demás está hecho.

Ahora quizás os expliquéis por qué a veces un mismo programa tarda tanto a arrancar unas veces y otras tan poco, sobre todo en las RT que son extremadamente lentas. Todo dependerá de si está en memoria y cuántas partes haya en la citada caché de aplicaciones.

El número de aplicaciones guardadas es de cinco (si no lo han cambiado), pero dependiendo de la memoria del sistema y su carga, podrían ser más o menos. Tampoco hay un esquema claro de almacenamiento/descarte, puesto que entran en juego otras partes no Modern UI de Windows, como la memoria virtual y la caché de disco.

Por lo tanto, si tu costumbre es utilizar las mismas cinco o menos aplicaciones a la vez, tu tableta tendrá un rendimiento aceptable, pero si empiezas a usar más, o una que consuma mucha memoria, verás cómo el funcionamiento se degrada sensiblemente.

Dicho esto, el modelo está calcado de OS X (y supongo que de iOS), con alguna mejora aunque no sé hasta el nivel que ha llegado Mavericks y Yosemite, ya que desde que tengo instalado el primero de ellos ya no he tenido problemas con la memoria de mis MAC y no me he metido en detalles sobre cómo funciona.

Microsoft ha implementado una serie de trucos para manejar estos escenarios, trucos que puede utilizar el usuario normal pero que han cambiado de Windows 8 a 8.1, a mejor desde mi punto de vista.

Con estos trucos muchas veces podremos hacer volver al redil a una aplicación cuyo comportamiento se haya estropeado sin tener que reinstalarla, cosa que a veces, si no aplicas uno de estos trucos, no funciona porque si nos quejábamos de que una desinstalación de un programa nativo Win32 dejaba rastros y basura en Windows, con las aplicaciones Modern UI apenas se elimina nada, quedando almacenados la mayoría de datos de la aplicación, cachés de disco, optimizaciones, etc, y que solo se borrarán cuando la aplicación haya desaparecido de todos nuestros Windows y hayan transcurrido unas semanas (suponiendo que se borren, no lo he comprobado experimentalmente). La ventaja de esto es que si reinstalas ya lo tienes todo preparado, pero si has reinstalado por un problema, lo más seguro es que el problema siga estando ahí.

Ojo, no estoy criticando, estoy explicando un hecho.

Volviendo a los trucos, podemos hacer dos cosas: matar una aplicación Modern UI o reiniciarla al mismo estilo que reinciamos Windows.

El proceso comienza igual: con el dedo (o el ratón) posicionado en la parte superior de la pantalla de la aplicación, desplazamos hasta casi abajo del todo. Ojo: no soltar o no haremos nada.

Si seguimos hacia abajo desplazando el dedo hasta que se salga de la pantalla de forma continua, hemos cerrado la aplicación igual que si hubiéramos apretado el botón de Windows o hubiéramos cambiado a otra aplicación.

Sin embargo, si cuando estamos casi abajo del todo, esperamos unos instantes, veremos cómo la aplicación se voltea y se queda enseñando el icono por defecto o la pantalla de Splash.

En ese momento se ha producido una situación en la que la aplicación ha perdido todos sus datos temporales y cachés y ficheros que tuviera abiertos en ese instante, pero todavía continua en memoria.

Si después de eso seguimos con el dedo hacia abajo, es equivalente a cerrarla  la aspa de cierre desde el ratón pero con el añadido del borrado de los datos intermedios. El cierre es equivalente a dejar la huella pero no la aplicación en memoria. Es lo más cercano que tenemos a un cierre total en Modern UI sin hacer intervenir al administrador de programas.

Pero sin embargo, si en lugar de desplazar hacia abajo, movemos el dedo hacia arriba de nuevo y soltamos cuando esté casi arriba del todo, la aplicación se vuelve a cargar desde cero, con lo que por lo general los problemas que hubiera con ella se han resuelto.

Esa es, por ejemplo, la mejor forma de reiniciar la propia aplicación de la Tienda cuando se pone asquerosa y deja de funcionar como debe.

 

 

 

 

 

 

 

 

 

 

 

 

 

Por RFOG | 14 Comentarios | Enlaza esta entrada
contacto@wintablet.info tema WinTablet.info por Ángel García (Hal9000)