2008-12-03 18 views
14

Se me ha encomendado la tarea de encontrar (y posiblemente solucionar) algunos problemas graves de rendimiento con una aplicación Flex que nos fue entregada. La aplicación tomará de forma consistente entre el 50 y el 100% de la CPU en momentos en que simplemente está funcionando al ralentí y no debería estar haciendo nada.Perfiles de Flex: ¿qué está haciendo [enterFrameEvent]?

Mi primer paso fue ejecutar el generador de perfiles que viene con FlexBuilder. Esperaba encontrar algún método que estuviera ocupando la mayor parte del tiempo, mostrándome dónde estaba el cuello de botella. Sin embargo, tengo algo inesperado.

los 4 primeros métodos eran:

  • [enterFrameEvent] - 84% acumulativo, 32% Tiempo de auto
  • [cosechar] - 20% el tiempo acumulado y la auto
  • [Tincan] - 8% tiempo acumulado y auto
  • global.isNaN - 4% tiempo acumulado y auto

Todos los demás métodos tenían menos de 1% tanto para tiempo acumulado y auto.

De lo que he encontrado en línea, los [métodos entre corchetes] son ​​los que el perfilador enumera cuando no tiene un método Flex real para mostrar. Vi a alguien afirmar que [tincan] es el procesamiento de solicitudes RTMP, y supongo que [cosechar] es el recolector de basura.

¿Alguien sabe lo que [enterFrameEvent] está haciendo realmente? Supongo que es esencialmente la función "principal" para el ciclo de eventos, por lo que se espera un tiempo acumulado alto. ¿Pero por qué el tiempo del yo es tan alto? ¿Qué está pasando realmente? No esperaba que las partes internas del jugador ocupen tanto tiempo, especialmente porque en realidad no sucede nada en la aplicación (y no hay actualizaciones de UI).

¿Hay alguna buena manera de averiguar qué está pasando? I saber algo no está sucediendo (parece que debe haber algún tipo de espera ocupada u otro bucle fuera de control), pero el generador de perfiles no me está dando los resultados que esperaba. Mi siguiente paso será comenzar a agregar declaraciones de seguimiento de depuración en varios lugares para intentar rastrear lo que realmente está sucediendo, pero creo que tiene que haber una forma mejor.

Respuesta

1

Creo que su problema está en otra parte. Esto sucede porque Flex se basa en Flash y Flash dispara ese evento tan a menudo como la velocidad de fotogramas (es decir, 20-30 veces por segundo).

http://www.adobe.com/support/flash/action_scripts/actionscript_dictionary/actionscript_dictionary546.html

EDIT: No estoy diciendo que la solución sería reducir la tasa de fotogramas. Eso solo funcionaría si el evento que notaste fuera el problema. No estoy convencido de que eso sea realmente lo que está causando tus ralentizaciones. Puede ser el llamando al una función que está causando el problema ... pero ese evento en sí no lo es. Se supone que debe disparar mucho.

+0

he intentado jugar alrededor con la velocidad de fotogramas, pero no tuvo ningún efecto real en el rendimiento. Bajar demasiado la velocidad de fotogramas provocaría que los cambios de la interfaz de usuario se ejecuten demasiado lentamente y no solucionarían los problemas que estamos viendo. – Herms

+0

El problema es que el generador de perfiles afirma que el evento ITSELF está ocupando el 32% del tiempo de CPU (más lo que llama lleva un 84%). Esa es una cantidad de tiempo muy significativa para un evento. Algo está pasando, pero no puedo decir qué. – Herms

0

Justin, gracias por la respuesta. El problema no está en la ejecución de enterFrame, sino más bien tratando de hacer demasiado en cada iteración.

FYI: Casualmente, el póster original y yo estamos tratando con la misma aplicación. Hemos decidido eliminar todos los recursos de Degrafa a favor de ProgrammaticSkins. Informaré los hallazgos aquí cuando hayamos completado esto.

3

Algunas actualizaciones: No estamos haciendo nada en la aplicación que no sea escuchar eventos y usar enlaces ... es decir, no ChangeWatchers, no hay sondeo manual ... solo a la espera de eventos. Estamos conectados a FMS todo el tiempo, por lo que hay algunos gastos generales para eso, pero es mínimo. Los enlaces no son muy eficientes en Flex, y hemos descubierto que no es bueno agregar la palabra clave de metadatos [Bindable] directamente a las clases (en gran volumen, con muchas clases). No estamos haciendo mucho de esto, pero es una manera de sacar un poco más rendimiento de su aplicación. Si usa [Bindable (event = "usersUpdated")], tendrá control sobre el enlace, y solo se activará cuando envíe el evento (new Event ("usersUpdated")) dentro de una función de la clase, es decir, su setter para 'usuarios'.

Cualquiera que haya usado System.gc() en Flex o AIR le dirá que la recolección de basura de Flex es una broma. Es una característica parcialmente implementada y nadie confía en ella. También hay trucos para esto ... llámalo dos veces, espera un cuadro, llámalo de nuevo. Puede limpiar tus objetos viejos, pero no cruces los dedos ... Flex hace lo que quiere.

Además, use objetos temporales para disminuir el número de enlaces disparados. En lugar de ...

myUser.location = new Ubicación(); myUser.location.state = "CO"; myUser.location.city = "Denver";

hacer ...

var tempLoc: Localización = nueva ubicación(); tempLoc.state = "CO"; tempLoc.city = "Denver"; myUser.location = tempLoc;

Los antiguos fuegos 3 ataduras a nada ligados a la localización. *, Mientras que el segundo debe sólo el fuego de unión 1 (en realidad, por lo general es extra debido a la forma en Flex maneja.)

enlaces no va a matar a su aplicación hasta que tenga muchos de ellos en una aplicación visualmente rica ... el enlace y la representación parecen ser los trabajos más lentos de Flex.

Otra cosa interesante: crear una nueva aplicación Flex3 en Flex Builder y ejecutarla en el navegador. Nuestras pruebas mostraron que la CPU se mantiene entre el 8-10% en una MacBookPro (cuando la aplicación está inactiva y la ventana del navegador oculta). Nuestra aplicación ahora se ejecuta de manera constante en ~ 20% y mientras aumenta más para manejar los cambios de vista y similares, siempre vuelve a un nivel cercano al 20%. Nuestra preocupación inicial era que había una fuga de memoria o algo que se escapaba y que elevaría la CPU hasta un 40-50% (de nuevo, en el MBP ... todo en relación con esta máquina). Eliminamos todas las referencias a Degrafa y, aunque notamos un buen aumento en el rendimiento, no explicaba todo. Sin embargo, la aplicación Flex vacía fue esclarecedora: Flex en sí consume una CPU del 8-10% en todo momento, incluso cuando está inactivo.

Otro hallazgo más ... si usa Mate, tenga cuidado de cómo maneja las vistas de cambio. Es fácil tener activos disponibles y simplemente ocultar & deshabilitarlos cuando no están siendo utilizados, mediante el uso de un inyector y un enlace en MXML, pero Flex no es muy inteligente a la hora de ocultar/deshabilitar cosas. Lo mejor es crear las vistas sobre la marcha y destruirlas cuando hayan terminado. Aunque la creación inicial puede llevar más tiempo y habrá una espera más larga entre las vistas, use algo de magia de visualización (una barra de progreso, un disco giratorio, etc.) para indicar que la vista se está alternando, espere a la creación completa en la vista y luego desvanecerse en él.

Además, aléjese de ViewStack para aplicaciones visualmente ricas. Administra tu propia pila.

Hasta ahora, este hilo ha superado los problemas de rendimiento básicos comunes a cualquier idioma, pero Flex es un niño muy especial en muchos aspectos ("especial" no siempre se considera algo positivo). Hay innumerables trampas porque está construida sobre una plataforma muy visual, pero está diseñada para RIA, por lo que aunque Flash Player pueda optimizar video, animaciones, etc., no optimizará una aplicación Flex. No espere que las aplicaciones Flex tengan el mismo rendimiento que las aplicaciones Flash. También hay una gran diferencia entre AVM (máquina virtual ActionScript) para AS2 y AS3.

Esto simplemente está arañando la superficie de los problemas de rendimiento y las posibles ganancias en las aplicaciones de Flex. Este es un arte oscuro y es fácil ver por qué.

Code on, ninjas.

+0

Solo para tu información: una aplicación Flex vacía en mi máquina se ejecuta consistentemente al 0% de la CPU. Voy a probarlo en una vieja caja de mierda más tarde para ver si es diferente. Así que no creo que sea particularmente útil, ya que los problemas de rendimiento que tenemos en la aplicación también están en Windows. – Herms

5

Hay un par de cosas que normalmente ocurren en un controlador enterframe en un proyecto flexible. Algunas cosas que debe observar

  1. Manual < mycomponent enterFrame = ""> las respuestas de eventos o los añadidos manualmente a través de component.addEventListener (Event.ENTER_FRAME, myfunc)

  2. callLater() llama, estos resultan MUCHO en el marco y puede ser un subproducto de saltar cualquier número de agujeros de conejo, los desarrolladores tienden a utilizar estos mucho para resolver problemas relacionados con el tiempo y, a veces, el código incorrecto puede hacer que estos continúen llamando a cada fotograma. Por ejemplo, hay ~ 120 apariciones de un calllater() en la última versión de flex sdk.

  3. Por último, no puedo garantizar que el [enterframeEvent] maneja solo enterframe devoluciones de llamada de eventos específicos, y no temporizadores, mouse, etc. eventos, ya que enterframes ocurren durante el evento principal, puede estar viendo el cumulativo resultado de todos los eventos activados desde el grupo de eventos principal. No estoy diciendo que esto ES lo que está pasando, pero tampoco puedo decir que NO ES lo que está sucediendo, no sé lo suficiente acerca de las partes internas para estar seguro.

/editar también como se dijo anteriormente, el [enterFrameEvent] debería técnicamente disparar internamente en el inicio de cada trama, pero no se debe hacer nada a no ser que los acontecimientos se han unido de forma explícita a él para ejecutar código de usuario.

+0

Pero cualquier método pasado a callLater o agregado como oyentes debe aparecer en el generador de perfiles, ¿no es así? Dado que esos serían métodos AS3 reales, esperaría que se mostrara el tiempo en esos métodos, no dentro de enterFrameEvent. Eso es lo extraño. – Herms

+0

Sí y no, enterframeEvent sería un acumulativo de todo lo que sucede, si tenía 10 o 20 devoluciones de llamadas procesadas durante ese evento, todas podrían ser menores y no registrarse tanto en el generador de perfiles por separado, pero juntas representan una gran cantidad de tiempo. – seanalltogether

+0

El generador de perfiles muestra 2 estadísticas. Acumulativo y Self. Acumulativo es de lo que estás hablando. Creo que el Sí mismo es cuánto tiempo se gasta en ese método específicamente, y no en los otros métodos perfilados. – Herms

3

Una actualización de este puesto debe venir a través de cualquier persona en el futuro ...

Unos compañeros de trabajo en EffectiveUI tenían este problema exacto con su aplicación un par de meses más tarde, por lo que fue revisado. Se descubrió que al usar Flash para producir activos visuales, al usar STATEFUL SKINS y exportarlos a SWC con el kit de herramientas de activos de Flash/Flex, obtiene películas fugitivas (presumiblemente algo interno en la forma en que esto se implementa, por ejemplo, olvidando poner comandos stop() en marcos).

Aparentemente no hay nada que pueda hacer al respecto, excepto para entrar y eliminar todas las máscaras con estado. Un buen reportaje se puede encontrar aquí:

http://patrickhansen.com/blog/index.php/2009/03/05/flex-stateful-skins-vs-stateless?blog=3

y un guión JSFL que se puede utilizar para convertir pieles con estado a los apátridas pieles:

http://patrickhansen.com/blog/index.php/2009/04/08/stateful-to-stateless-jsfl-flash-command?blog=3

Espero que esto ayude a alguien! Es un error muy desagradable y misterioso, pero puedes evitarlo.

Saludos

Cuestiones relacionadas